Skip to content

Commit 5cacd1b

Browse files
committed
[ConstraintSystem] Fix situations when contextual base type can't be inferred
It might be either impossible to infer the base because there is no contextual information e.g. `_ = .foo` or there is something else wrong in the expression which disconnects member reference from its context.
1 parent 3c5290c commit 5cacd1b

File tree

8 files changed

+40
-9
lines changed

8 files changed

+40
-9
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,13 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
738738
if (shouldAttemptFixes() && result.Bindings.empty() &&
739739
typeVar->getImpl().canBindToHole()) {
740740
result.IsHole = true;
741+
// If the base of the unresolved member reference like `.foo`
742+
// couldn't be resolved we'd want to bind it to a hole at the
743+
// very last moment possible, just like generic parameters.
744+
auto *locator = typeVar->getImpl().getLocator();
745+
if (locator->isLastElement<LocatorPathElt::MemberRefBase>())
746+
result.PotentiallyIncomplete = true;
747+
741748
result.addPotentialBinding({getASTContext().TheUnresolvedType,
742749
AllowedBindingKind::Exact, ConstraintKind::Defaultable, nullptr,
743750
typeVar->getImpl().getLocator()});

lib/Sema/CSGen.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,10 +1507,13 @@ namespace {
15071507

15081508
auto memberLocator
15091509
= CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember);
1510-
auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape);
1511-
auto memberTy = CS.createTypeVariable(memberLocator,
1512-
TVO_CanBindToLValue |
1513-
TVO_CanBindToNoEscape);
1510+
1511+
// Since base type in this case is completely dependent on context it
1512+
// should be marked as a potential hole.
1513+
auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape |
1514+
TVO_CanBindToHole);
1515+
auto memberTy = CS.createTypeVariable(
1516+
memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape);
15141517

15151518
// An unresolved member expression '.member' is modeled as a value member
15161519
// constraint

lib/Sema/CSSimplify.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6059,6 +6059,23 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
60596059
Type baseObjTy = baseTy->getRValueType();
60606060

60616061
auto locator = getConstraintLocator(locatorB);
6062+
6063+
// If this is an unresolved member ref e.g. `.foo` and its contextual base
6064+
// type has been determined to be a "hole", let's mark the resulting member
6065+
// type as a potential hole and continue solving.
6066+
if (shouldAttemptFixes() && kind == ConstraintKind::UnresolvedValueMember &&
6067+
baseObjTy->getMetatypeInstanceType()->isHole()) {
6068+
auto *fix =
6069+
SpecifyBaseTypeForContextualMember::create(*this, member, locator);
6070+
if (recordFix(fix))
6071+
return SolutionKind::Error;
6072+
6073+
if (auto *typeVar = memberTy->getAs<TypeVariableType>())
6074+
recordPotentialHole(typeVar);
6075+
6076+
return SolutionKind::Solved;
6077+
}
6078+
60626079
MemberLookupResult result =
60636080
performMemberLookup(kind, member, baseTy, functionRefKind, locator,
60646081
/*includeInaccessibleMembers*/ shouldAttemptFixes());
@@ -8449,6 +8466,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
84498466
case FixKind::ExpandArrayIntoVarargs:
84508467
case FixKind::UseValueTypeOfRawRepresentative:
84518468
case FixKind::ExplicitlyConstructRawRepresentable:
8469+
case FixKind::SpecifyBaseTypeForContextualMember:
84528470
case FixKind::CoerceToCheckedCast: {
84538471
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
84548472
}

test/Constraints/construction.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Optional<Int>(1) // expected-warning{{unused}}
6060
Optional(1) // expected-warning{{unused}}
6161
_ = .none as Optional<Int>
6262
Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}} {{9-9=<Any>}}
63+
// expected-error@-1 {{cannot infer contextual base in reference to member 'none'}}
6364

6465
// Interpolation
6566
_ = "\(hello), \(world) #\(i)!"

test/Constraints/diagnostics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,8 @@ enum Color {
498498
static var svar: Color { return .Red }
499499
}
500500

501-
// FIXME: This used to be better: "'map' produces '[T]', not the expected contextual result type '(Int, Color)'"
502-
let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) }) // expected-error {{expression type '((Int) throws -> _) throws -> Array<_>' is ambiguous without more context}}
501+
let _: (Int, Color) = [1,2].map({ ($0, .Unknown("")) }) // expected-error {{cannot convert value of type 'Array<(Int, _)>' to specified type '(Int, Color)'}}
502+
// expected-error@-1 {{cannot infer contextual base in reference to member 'Unknown'}}
503503

504504
let _: [(Int, Color)] = [1,2].map({ ($0, .Unknown("")) })// expected-error {{missing argument label 'description:' in call}}
505505

test/Constraints/members.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ enum r23942743 {
325325
case Tomato(cloud: String)
326326
}
327327
let _ = .Tomato(cloud: .none) // expected-error {{reference to member 'Tomato' cannot be resolved without a contextual type}}
328+
// expected-error@-1 {{cannot infer contextual base in reference to member 'none'}}
328329

329330

330331

test/Sema/diag_ambiguous_overloads.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ struct S {
2626
f({x in x}, 2) // expected-error {{generic parameter 'T' could not be inferred}}
2727
}
2828

29-
func g<T>(_ a: T, _ b: Int) -> Void {} // expected-note {{in call to function 'g'}}
29+
func g<T>(_ a: T, _ b: Int) -> Void {}
3030
func g(_ a: String) -> Void {}
3131
func test2() -> Void {
32-
g(.notAThing, 7) // expected-error {{generic parameter 'T' could not be inferred}}
32+
g(.notAThing, 7) // expected-error {{cannot infer contextual base in reference to member 'notAThing'}}
3333
}
3434

3535
func h(_ a: Int, _ b: Int) -> Void {}

test/decl/enum/enumtest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ func test3a(_ a: ZeroOneTwoThree) {
100100
// Overload resolution can resolve this to the right constructor.
101101
var h = ZeroOneTwoThree(1)
102102

103-
var i = 0 > 3 ? .none : .some(3) // expected-error {{reference to member 'none' cannot be resolved without a contextual type}}
103+
var i = 0 > 3 ? .none : .some(3) // expected-error {{cannot infer contextual base in reference to member 'none'}}
104+
// expected-error@-1 {{cannot infer contextual base in reference to member 'some'}}
104105

105106
test3a; // expected-error {{unused function}}
106107
.Zero // expected-error {{reference to member 'Zero' cannot be resolved without a contextual type}}

0 commit comments

Comments
 (0)