Skip to content

Commit

Permalink
[RequirementMachine] When computing requirements for conflict diagnos…
Browse files Browse the repository at this point in the history
…tics,

adjust the concrete type symbol for the suffix rule by applying the prefix
from the subject rule.
  • Loading branch information
hborla committed Mar 31, 2022
1 parent 78b0756 commit 7e5c483
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 24 deletions.
19 changes: 12 additions & 7 deletions lib/AST/RequirementMachine/RewriteSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,19 +756,20 @@ void RewriteSystem::freeze() {
static Optional<Requirement>
getRequirementForDiagnostics(Type subject, Symbol property,
const PropertyMap &map,
TypeArrayView<GenericTypeParamType> genericParams) {
TypeArrayView<GenericTypeParamType> genericParams,
const MutableTerm &prefix) {
switch (property.getKind()) {
case Symbol::Kind::ConcreteType: {
auto concreteType = map.getTypeFromSubstitutionSchema(
property.getConcreteType(), property.getSubstitutions(),
genericParams, MutableTerm());
genericParams, prefix);
return Requirement(RequirementKind::SameType, subject, concreteType);
}

case Symbol::Kind::Superclass: {
auto concreteType = map.getTypeFromSubstitutionSchema(
property.getConcreteType(), property.getSubstitutions(),
genericParams, MutableTerm());
genericParams, prefix);
return Requirement(RequirementKind::Superclass, subject, concreteType);
}

Expand Down Expand Up @@ -799,17 +800,21 @@ void RewriteSystem::computeConflictDiagnostics(
auto subjectRule = chooseFirstRule ? firstRule : secondRule;
auto subjectTerm = subjectRule.getRHS();

auto suffixRule = chooseFirstRule ? secondRule : firstRule;
auto suffixTerm = suffixRule.getRHS();

// If the root protocol of the subject term isn't in this minimization
// domain, the conflict was already diagnosed.
if (!isInMinimizationDomain(subjectTerm[0].getRootProtocol()))
continue;

Type subject = propertyMap.getTypeForTerm(subjectTerm, genericParams);
MutableTerm prefix(subjectTerm.begin(), subjectTerm.end() - suffixTerm.size());
errors.push_back(RequirementError::forConflictingRequirement(
*getRequirementForDiagnostics(subject, *firstRule.isPropertyRule(),
propertyMap, genericParams),
*getRequirementForDiagnostics(subject, *secondRule.isPropertyRule(),
propertyMap, genericParams),
*getRequirementForDiagnostics(subject, *subjectRule.isPropertyRule(),
propertyMap, genericParams, MutableTerm()),
*getRequirementForDiagnostics(subject, *suffixRule.isPropertyRule(),
propertyMap, genericParams, prefix),
signatureLoc));
}
}
Expand Down
8 changes: 4 additions & 4 deletions test/Generics/concrete_conflict.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ protocol P3 {
// CHECK-LABEL: .P4@
// CHECK-LABEL: Requirement signature: <Self where Self.[P4]T : P1, Self.[P4]T : P2, Self.[P4]T : P3>

// expected-error@+3{{no type for 'Self.T.T' can satisfy both 'Self.T.T == Int' and 'Self.T.T == String'}}
// expected-error@+2{{no type for 'Self.T.T' can satisfy both 'Self.T.T == Int' and 'Self.T.T == Float'}}
// expected-error@+1{{no type for 'Self.T.T' can satisfy both 'Self.T.T == String' and 'Self.T.T == Float'}}
// expected-error@+3{{no type for 'Self.T.T' can satisfy both 'Self.T.T == String' and 'Self.T.T == Int'}}
// expected-error@+2{{no type for 'Self.T.T' can satisfy both 'Self.T.T == Float' and 'Self.T.T == Int'}}
// expected-error@+1{{no type for 'Self.T.T' can satisfy both 'Self.T.T == Float' and 'Self.T.T == String'}}
protocol P4 {
associatedtype T : P1 & P2 & P3
}
Expand All @@ -37,5 +37,5 @@ extension Class where T == Bool {
// CHECK-LABEL: .badRequirement()@
// CHECK-NEXT: <T>
func badRequirement() where T == Int { }
// expected-error@-1 {{no type for 'T' can satisfy both 'T == Bool' and 'T == Int'}}
// expected-error@-1 {{no type for 'T' can satisfy both 'T == Int' and 'T == Bool'}}
}
2 changes: 1 addition & 1 deletion test/Generics/protocol_self_concrete_error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@

struct S {}

// expected-error@+1 {{no type for 'Self' can satisfy both 'Self : P' and 'Self == S'}}
// expected-error@+1 {{no type for 'Self' can satisfy both 'Self == S' and 'Self : P'}}
protocol P where Self == S {}
24 changes: 12 additions & 12 deletions test/Generics/requirement_machine_diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ protocol ProtoAlias2 {
}

func basicConflict<T: ProtoAlias1 & ProtoAlias2>(_:T) where T.A1 == T.A2 {}
// expected-error@-1{{no type for 'T.A1' can satisfy both 'T.A1 == Int' and 'T.A1 == String'}}
// expected-error@-1{{no type for 'T.A1' can satisfy both 'T.A1 == String' and 'T.A1 == Int'}}

protocol RequiresAnyObject {
associatedtype A: AnyObject
Expand All @@ -231,14 +231,14 @@ func testMissingRequirements() {
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A == S' and 'T.A : AnyObject'}}

func conflict2<T: RequiresConformance>(_: T) where T.A == C {}
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A : P' and 'T.A == C'}}
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A == C' and 'T.A : P'}}

class C {}
func conflict3<T: RequiresSuperclass>(_: T) where T.A == C {}
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A : Super' and 'T.A : C'}}
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A : C' and 'T.A : Super'}}

func conflict4<T: RequiresSuperclass>(_: T) where T.A: C {}
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A : Super' and 'T.A : C'}}
// expected-error@-1{{no type for 'T.A' can satisfy both 'T.A : C' and 'T.A : Super'}}
}

protocol Fooable {
Expand All @@ -265,51 +265,51 @@ func sameTypeConflicts() {
var bar: Y { return Y() }
}

// expected-error@+1{{no type for 'T.Foo' can satisfy both 'T.Foo == Y' and 'T.Foo == X'}}
// expected-error@+1{{no type for 'T.Foo' can satisfy both 'T.Foo == X' and 'T.Foo == Y'}}
func fail1<
T: Fooable, U: Fooable
>(_ t: T, u: U) -> (X, Y)
where T.Foo == X, U.Foo == Y, T.Foo == U.Foo {
fatalError()
}

// expected-error@+1{{no type for 'T.Foo' can satisfy both 'T.Foo == X' and 'T.Foo == Y'}}
// expected-error@+1{{no type for 'T.Foo' can satisfy both 'T.Foo == Y' and 'T.Foo == X'}}
func fail2<
T: Fooable, U: Fooable
>(_ t: T, u: U) -> (X, Y)
where T.Foo == U.Foo, T.Foo == X, U.Foo == Y {
fatalError()
}

// expected-error@+1{{no type for 'T.Bar' can satisfy both 'T.Bar : Fooable' and 'T.Bar == X'}}
// expected-error@+1{{no type for 'T.Bar' can satisfy both 'T.Bar == X' and 'T.Bar : Fooable'}}
func fail3<T: Barrable>(_ t: T) -> X
where T.Bar == X {
fatalError()
}

// expected-error@+1{{no type for 'T.Bar.Foo' can satisfy both 'T.Bar.Foo == Z' and 'T.Bar.Foo == X'}}
// expected-error@+1{{no type for 'T.Bar.Foo' can satisfy both 'T.Bar.Foo == X' and 'T.Bar.Foo == Z'}}
func fail4<T: Barrable>(_ t: T) -> (Y, Z)
where
T.Bar == Y,
T.Bar.Foo == Z {
fatalError()
}

// expected-error@+1{{no type for 'T.Bar.Foo' can satisfy both 'T.Bar.Foo == Z' and 'T.Bar.Foo == X'}}
// expected-error@+1{{no type for 'T.Bar.Foo' can satisfy both 'T.Bar.Foo == X' and 'T.Bar.Foo == Z'}}
func fail5<T: Barrable>(_ t: T) -> (Y, Z)
where
T.Bar.Foo == Z,
T.Bar == Y {
fatalError()
}

// expected-error@+1{{no type for 'T.X' can satisfy both 'T.X == Int' and 'T.X == String'}}
// expected-error@+1{{no type for 'T.X' can satisfy both 'T.X == String' and 'T.X == Int'}}
func fail6<U, T: Concrete>(_: U, _: T) where T.X == String {}

struct G<T> {}

// FIXME: conflict diagnosed twice
// expected-error@+1 2{{no type for 'T.X' can satisfy both 'T.X == Int' and 'T.X == G<U.Foo>'}}
// expected-error@+1 2{{no type for 'T.X' can satisfy both 'T.X == G<U.Foo>' and 'T.X == Int'}}
func fail7<U: Fooable, T: Concrete>(_: U, _: T) where T.X == G<U.Foo> {}

// FIXME: conflict diagnosed twice
Expand All @@ -318,6 +318,6 @@ func sameTypeConflicts() {
func fail8<T, U: Fooable>(_: U, _: T) where T == G<U.Foo>, T == Int {}

// FIXME: conflict diagnosed twice
// expected-error@+1 2{{no type for 'T' can satisfy both 'T == Int' and 'T == G<U.Foo>'}}
// expected-error@+1 2{{no type for 'T' can satisfy both 'T == G<U.Foo>' and 'T == Int'}}
func fail9<T, U: Fooable>(_: U, _: T) where T == Int, T == G<U.Foo> {}
}

0 comments on commit 7e5c483

Please sign in to comment.