I've been reworking the constraint generation for UnresolvedMemberExpr
s, and am hitting an issue with the following simple snippet of code:
struct S {
static var string = ""
}
let _: S = .string
Obviously, this shouldn't compile. There are type variables for the (implicit) base of the member reference ($T0
), the result of the member access ($T1
), and the contextual type of the expression ($T2
). Constraints are specified such that $T0
and $T1
must be convertible to $T2
. As expected, the first pass at solving this system fails:
(solving component #0
($T2 involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T2 := S
(attempting type variable $T2 := S
($T0 bindings={(subtypes of) S})
($T1 fully_bound involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T0 := S
(attempting type variable $T0 := S
(overload set choice binding $T1 := @lvalue String)
(failed constraint $T1 conv $T2 [[locator@0x11d043c20 [UnresolvedMember@/Users/freddy/Development/scratch/test.swift:7:13 -> unresolved member]]];)
)
)
failed component #0)
However, the solver then enters the salvage stage, where this happens:
(solving component #0
($T0 potentially_incomplete involves_type_vars #defaultable_bindings=1 bindings={<<unresolvedtype>>})
($T2 involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T2 := S
(attempting type variable $T2 := S
($T0 bindings={(subtypes of) S})
($T1 fully_bound involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T0 := S
(attempting type variable $T0 := S
(overload set choice binding $T1 := @lvalue String)
(found solution 0 0 0 0 0 0 0 0 0 0 0 0 0)
)
)
finished component #0)
(composed solution 0 0 0 0 0 0 0 0 0 0 0 0 0)
The full solution is,
$T2 as S
$T1 as @lvalue String
$T0 as S
which causes a crash down the line when the compiler attempts to coerce an @lvalue String
to an S
.
What is different about the salvage()
pass that allows the above solution to be considered a success? If anyone has an idea of what's going on here, I'd appreciate any advice they can provide!
The full output of the solution process (cleaned up a bit for noise) can be found here:
Full output
Score: 0 0 0 0 0 0 0 0 0 0 0 0 0
Contextual Type: S at [test.swift:7:8 - line:7:8]
Type Variables:
$T0 [noescape allowed] potentially_incomplete involves_type_vars #defaultable_bindings=1 bindings={<<unresolvedtype>>} @ locator@1 [UnresolvedMember@test.swift:7:13 -> member reference base]
$T1 [lvalue allowed] [noescape allowed] fully_bound subtype_of_existential involves_type_vars bindings={} @ locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]
$T2 [lvalue allowed] [noescape allowed] involves_type_vars bindings={(subtypes of) S} @ locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]
$T3 [noescape allowed] bindings={(subtypes of) S} @ locator@3 [UnresolvedMember@test.swift:7:13 -> contextual type -> pattern match]
Active Constraints:
Inactive Constraints:
$T0.Type[(implicit) .string: value] == $T1 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T1 conv $T2 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T0 conv $T2 [[locator@4 [UnresolvedMember@test.swift:7:13 -> rvalue adjustment]]];
$T3 conv S [[locator@5 [UnresolvedMember@test.swift:7:13 -> contextual type -> pattern match]]];
$T2 conv S [[locator@6 [UnresolvedMember@test.swift:7:13 -> contextual type]]];
---Constraint graph---
$T0:
Constraints:
$T0.Type[(implicit) .string: value] == $T1 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T0 conv $T2 [[locator@4 [UnresolvedMember@test.swift:7:13 -> rvalue adjustment]]];
$T1:
Constraints:
$T0.Type[(implicit) .string: value] == $T1 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T1 conv $T2 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T2:
Constraints:
$T1 conv $T2 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T0 conv $T2 [[locator@4 [UnresolvedMember@test.swift:7:13 -> rvalue adjustment]]];
$T2 conv S [[locator@6 [UnresolvedMember@test.swift:7:13 -> contextual type]]];
$T3:
Constraints:
$T3 conv S [[locator@5 [UnresolvedMember@test.swift:7:13 -> contextual type -> pattern match]]];
---Connected components---
0: $T0 $T1 $T2
1: $T3
(solving component #1
($T3 bindings={(subtypes of) S})
Initial bindings: $T3 := S
(attempting type variable $T3 := S
(found solution 0 0 0 0 0 0 0 0 0 0 0 0 0)
)
finished component #1)
(solving component #0
($T2 involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T2 := S
(attempting type variable $T2 := S
($T0 bindings={(subtypes of) S})
($T1 fully_bound involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T0 := S
(attempting type variable $T0 := S
(overload set choice binding $T1 := @lvalue String)
(failed constraint $T1 conv $T2 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];)
)
)
failed component #0)
---Solver statistics---
Total number of scopes explored: 6
Maximum depth reached while exploring solutions: 4
Time: 2.651000e+00ms
---Attempting to salvage and emit diagnostics---
---Constraint graph---
$T0:
Constraints:
$T0.Type[(implicit) .string: value] == $T1 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T0 conv $T2 [[locator@4 [UnresolvedMember@test.swift:7:13 -> rvalue adjustment]]];
$T1:
Constraints:
$T0.Type[(implicit) .string: value] == $T1 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T1 conv $T2 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T2:
Constraints:
$T1 conv $T2 [[locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]]];
$T0 conv $T2 [[locator@4 [UnresolvedMember@test.swift:7:13 -> rvalue adjustment]]];
$T2 conv S [[locator@6 [UnresolvedMember@test.swift:7:13 -> contextual type]]];
$T3:
Constraints:
$T3 conv S [[locator@5 [UnresolvedMember@test.swift:7:13 -> contextual type -> pattern match]]];
---Connected components---
0: $T0 $T1 $T2
1: $T3
(solving component #1
($T3 bindings={(subtypes of) S})
Initial bindings: $T3 := S
(attempting type variable $T3 := S
(found solution 0 0 0 0 0 0 0 0 0 0 0 0 0)
)
finished component #1)
(solving component #0
($T0 potentially_incomplete involves_type_vars #defaultable_bindings=1 bindings={<<unresolvedtype>>})
($T2 involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T2 := S
(attempting type variable $T2 := S
($T0 bindings={(subtypes of) S})
($T1 fully_bound involves_type_vars bindings={(subtypes of) S})
Initial bindings: $T0 := S
(attempting type variable $T0 := S
(overload set choice binding $T1 := @lvalue String)
(found solution 0 0 0 0 0 0 0 0 0 0 0 0 0)
)
)
finished component #0)
(composed solution 0 0 0 0 0 0 0 0 0 0 0 0 0)
---Solution---
Fixed score: 0 0 0 0 0 0 0 0 0 0 0 0 0
Type variables:
$T2 as S @ locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]
$T1 as @lvalue String @ locator@2 [UnresolvedMember@test.swift:7:13 -> unresolved member]
$T0 as S @ locator@1 [UnresolvedMember@test.swift:7:13 -> member reference base]
$T3 as S @ locator@3 [UnresolvedMember@test.swift:7:13 -> contextual type -> pattern match]