Skip to content

Commit

Permalink
[GSB] Centralize diagnosis of concrete types and conformance requirem…
Browse files Browse the repository at this point in the history
…ents.

Ensures that we don't admit invalid cases where the concrete type does
not conform to the required protocol.
  • Loading branch information
DougGregor committed Jun 24, 2017
1 parent 791ac7f commit c879b95
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 18 deletions.
35 changes: 18 additions & 17 deletions lib/AST/GenericSignatureBuilder.cpp
Expand Up @@ -1326,15 +1326,6 @@ GenericSignatureBuilder::resolveConcreteConformance(PotentialArchetype *pa,
auto concrete = pa->getConcreteType();
if (!concrete) return nullptr;

// Lookup the conformance of the concrete type to this protocol.
auto conformance =
getLookupConformanceFn()(pa->getDependentType({ }, /*allowUnresolved=*/true)
->getCanonicalType(),
concrete,
proto->getDeclaredInterfaceType()
->castTo<ProtocolType>());
if (!conformance) return nullptr;

// Conformance to this protocol is redundant; update the requirement source
// appropriately.
auto paEquivClass = pa->getOrCreateEquivalenceClass();
Expand All @@ -1345,6 +1336,23 @@ GenericSignatureBuilder::resolveConcreteConformance(PotentialArchetype *pa,
else
concreteSource = paEquivClass->concreteTypeConstraints.front().source;

// Lookup the conformance of the concrete type to this protocol.
auto conformance =
getLookupConformanceFn()(pa->getDependentType({ }, /*allowUnresolved=*/true)
->getCanonicalType(),
concrete,
proto->getDeclaredInterfaceType()
->castTo<ProtocolType>());
if (!conformance) {
if (!concrete->hasError() && concreteSource->getLoc().isValid()) {
Diags.diagnose(concreteSource->getLoc(),
diag::requires_generic_param_same_type_does_not_conform,
concrete, proto->getName());
}

return nullptr;
}

concreteSource = concreteSource->viaConcrete(*this, *conformance);
paEquivClass->conformsTo[proto].push_back({pa, proto, concreteSource});
++NumConformanceConstraints;
Expand Down Expand Up @@ -3454,15 +3462,8 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete(
// Make sure the concrete type fulfills the conformance requirements of
// this equivalence class.
for (auto protocol : rep->getConformsTo()) {
if (!resolveConcreteConformance(rep, protocol)) {
if (!Concrete->hasError() && Source->getLoc().isValid()) {
Diags.diagnose(Source->getLoc(),
diag::requires_generic_param_same_type_does_not_conform,
Concrete, protocol->getName());
}

if (!resolveConcreteConformance(rep, protocol))
return ConstraintResult::Conflicting;
}
}

// Eagerly resolve any existing nested types to their concrete forms (others
Expand Down
11 changes: 10 additions & 1 deletion test/Constraints/same_types.swift
Expand Up @@ -88,7 +88,7 @@ func test6<T: Barrable>(_ t: T) -> (Y, X) where T.Bar == Y {

func test7<T: Barrable>(_ t: T) -> (Y, X) where T.Bar == Y, T.Bar.Foo == X {
// expected-warning@-1{{redundant same-type constraint 'T.Bar.Foo' == 'X'}}
// expected-note@-2{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}}
// expected-note@-2{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}}
return (t.bar, t.bar.foo)
}

Expand Down Expand Up @@ -241,5 +241,14 @@ func structuralSameTypeRecursive1<T: P2, U>(_: T, _: U)
{ }


protocol P3 {
}

protocol P4 {
associatedtype A
}

func test9<T>(_: T) where T.A == X, T: P4, T.A: P3 { } // expected-error{{same-type constraint type 'X' does not conform to required protocol 'P3'}}

// FIXME: Remove -verify-ignore-unknown.
// <unknown>:0: error: unexpected error produced: generic parameter τ_0_0.Bar.Foo cannot be equal to both 'Y.Foo' (aka 'X') and 'Z'

0 comments on commit c879b95

Please sign in to comment.