@@ -2299,9 +2299,71 @@ namespace {
2299
2299
locator);
2300
2300
}
2301
2301
2302
- // If we have a type to ascribe to the variable, do so now.
2303
- if (oneWayVarType)
2302
+ // Ascribe a type to the declaration so it's always available to
2303
+ // constraint system.
2304
+ if (oneWayVarType) {
2304
2305
CS.setType (var, oneWayVarType);
2306
+ } else if (externalPatternType) {
2307
+ // If there is an externally imposed type, that's what the
2308
+ // declaration is going to be bound to.
2309
+ CS.setType (var, externalPatternType);
2310
+ } else {
2311
+ // Otherwise, let's use the type of the pattern. The type
2312
+ // of the declaration has to be r-value, so let's add an
2313
+ // equality constraint if pattern type has any type variables
2314
+ // that are allowed to be l-value.
2315
+ bool foundLValueVars = false ;
2316
+
2317
+ // Note that it wouldn't be always correct to allocate a single type
2318
+ // variable, that disallows l-value types, to use as a declaration
2319
+ // type because equality constraint would drop TVO_CanBindToLValue
2320
+ // from the right-hand side (which is not the case for `OneWayEqual`)
2321
+ // e.g.:
2322
+ //
2323
+ // sturct S { var x, y: Int }
2324
+ //
2325
+ // func test(s: S) {
2326
+ // let (x, y) = (s.x, s.y)
2327
+ // }
2328
+ //
2329
+ // Single type variable approach results in the following constraint:
2330
+ // `$T_x_y = ($T_s_x, $T_s_y)` where both `$T_s_x` and `$T_s_y` have
2331
+ // to allow l-value, but `$T_x_y` does not. Early simplication of `=`
2332
+ // constraint (due to right-hand side being a "concrete" tuple type)
2333
+ // would drop l-value option from `$T_s_x` and `$T_s_y` which leads to
2334
+ // a failure during member lookup because `x` and `y` are both
2335
+ // `@lvalue Int`. To avoid that, declaration type would mimic pattern
2336
+ // type with all l-value options stripped, so the equality constraint
2337
+ // becomes `($T_x, $_T_y) = ($T_s_x, $T_s_y)` which doesn't result in
2338
+ // stripping of l-value flag from the right-hand side since
2339
+ // simplification can only happen when either side is resolved.
2340
+ auto declTy = varType.transform ([&](Type type) -> Type {
2341
+ if (auto *typeVar = type->getAs <TypeVariableType>()) {
2342
+ if (typeVar->getImpl ().canBindToLValue ()) {
2343
+ foundLValueVars = true ;
2344
+
2345
+ // Drop l-value from the options but preserve the rest.
2346
+ auto options = typeVar->getImpl ().getRawOptions ();
2347
+ options &= ~TVO_CanBindToLValue;
2348
+
2349
+ return CS.createTypeVariable (typeVar->getImpl ().getLocator (),
2350
+ options);
2351
+ }
2352
+ }
2353
+ return type;
2354
+ });
2355
+
2356
+ // If pattern types allows l-value types, let's create an
2357
+ // equality constraint between r-value only declaration type
2358
+ // and l-value pattern type that would take care of looking
2359
+ // through l-values when necessary.
2360
+ if (foundLValueVars) {
2361
+ CS.addConstraint (ConstraintKind::Equal, declTy, varType,
2362
+ CS.getConstraintLocator (locator));
2363
+ }
2364
+
2365
+ CS.setType (var, declTy);
2366
+ }
2305
2367
2306
2368
return setType (varType);
2307
2369
}
0 commit comments