@@ -309,42 +309,7 @@ func (interpreter *Interpreter) memberExpressionGetterSetter(
309
309
// e.g.1: Given type T, this method returns &T.
310
310
// e.g.2: Given T?, this returns (&T)?
311
311
func (interpreter * Interpreter ) getReferenceValue (value Value , resultType sema.Type , locationRange LocationRange ) Value {
312
-
313
- // `resultType` is always an [optional] reference.
314
- // This is guaranteed by the checker.
315
- referenceType , ok := sema .UnwrapOptionalType (resultType ).(* sema.ReferenceType )
316
- if ! ok {
317
- panic (errors .NewUnreachableError ())
318
- }
319
-
320
- switch value := value .(type ) {
321
- case NilValue , ReferenceValue :
322
- // Reference to a nil, should return a nil.
323
- // If the value is already a reference then return the same reference.
324
- // However, we need to make sure that this reference is actually a subtype of the resultType,
325
- // since the checker may not be aware that we are "short-circuiting" in this case
326
- // Additionally, it is only safe to "compress" reference types like this when the desired
327
- // result reference type is unauthorized
328
-
329
- staticType := value .StaticType (interpreter )
330
- if referenceType .Authorization != sema .UnauthorizedAccess || ! interpreter .IsSubTypeOfSemaType (staticType , resultType ) {
331
- panic (InvalidMemberReferenceError {
332
- ExpectedType : resultType ,
333
- ActualType : interpreter .MustConvertStaticToSemaType (staticType ),
334
- LocationRange : locationRange ,
335
- })
336
- }
337
-
338
- return value
339
-
340
- case * SomeValue :
341
- innerValue := interpreter .getReferenceValue (value .value , resultType , locationRange )
342
- return NewSomeValueNonCopying (interpreter , innerValue )
343
- }
344
-
345
- auth := ConvertSemaAccessToStaticAuthorization (interpreter , referenceType .Authorization )
346
-
347
- return NewEphemeralReferenceValue (interpreter , auth , value , referenceType .Type , locationRange )
312
+ return interpreter .createReference (resultType , value , locationRange , true )
348
313
}
349
314
350
315
func (interpreter * Interpreter ) checkMemberAccess (
@@ -1466,20 +1431,30 @@ func (interpreter *Interpreter) VisitReferenceExpression(referenceExpression *as
1466
1431
1467
1432
result := interpreter .evalExpression (referenceExpression .Expression )
1468
1433
1469
- return interpreter .createReference (borrowType , result , referenceExpression )
1434
+ locationRange := LocationRange {
1435
+ Location : interpreter .Location ,
1436
+ HasPosition : referenceExpression ,
1437
+ }
1438
+
1439
+ return interpreter .createReference (borrowType , result , locationRange , false )
1470
1440
}
1471
1441
1472
1442
func (interpreter * Interpreter ) createReference (
1473
1443
borrowType sema.Type ,
1474
1444
value Value ,
1475
- hasPosition ast.HasPosition ,
1445
+ locationRange LocationRange ,
1446
+ isImplicit bool ,
1476
1447
) Value {
1477
1448
1478
1449
// There are four potential cases:
1479
- // 1) Target type is optional, actual value is also optional (nil/SomeValue)
1480
- // 2) Target type is optional, actual value is non-optional
1481
- // 3) Target type is non-optional, actual value is optional (SomeValue)
1482
- // 4) Target type is non-optional, actual value is non-optional
1450
+ // (1) Target type is optional, actual value is also optional
1451
+ // (1.a) value is SomeValue
1452
+ // (1.b) value is nil
1453
+ // (2) Target type is optional, actual value is non-optional
1454
+ // (3) Target type is non-optional, actual value is optional
1455
+ // (3.a) value is SomeValue
1456
+ // (3.b) value is nil
1457
+ // (4) Target type is non-optional, actual value is non-optional
1483
1458
1484
1459
switch typ := borrowType .(type ) {
1485
1460
case * sema.OptionalType :
@@ -1489,48 +1464,75 @@ func (interpreter *Interpreter) createReference(
1489
1464
switch value := value .(type ) {
1490
1465
case * SomeValue :
1491
1466
// Case (1):
1492
- // References to optionals are transformed into optional references,
1493
- // so move the *SomeValue out to the reference itself
1467
+ // References to optionals are transformed into optional references.
1494
1468
1495
- locationRange := LocationRange {
1496
- Location : interpreter .Location ,
1497
- HasPosition : hasPosition ,
1498
- }
1469
+ // (1.a) value is SomeValue
1470
+ // Move the *SomeValue out to the reference itself.
1499
1471
1500
1472
innerValue := value .InnerValue (interpreter , locationRange )
1501
1473
1502
- referenceValue := interpreter .createReference (innerType , innerValue , hasPosition )
1474
+ referenceValue := interpreter .createReference (innerType , innerValue , locationRange , false )
1503
1475
1504
1476
// Wrap the reference with an optional (since an optional is expected).
1505
1477
return NewSomeValueNonCopying (interpreter , referenceValue )
1506
1478
1507
1479
case NilValue :
1480
+ // Case (1.b) value is nil.
1481
+ // Since the resulting type can accommodate a nil (optional-reference), return nil,
1508
1482
return Nil
1509
1483
1510
1484
default :
1511
1485
// Case (2):
1512
1486
// If the referenced value is non-optional,
1513
1487
// but the target type is optional.
1514
- referenceValue := interpreter .createReference (innerType , value , hasPosition )
1488
+ referenceValue := interpreter .createReference (innerType , value , locationRange , false )
1515
1489
1516
1490
// Wrap the reference with an optional (since an optional is expected).
1517
1491
return NewSomeValueNonCopying (interpreter , referenceValue )
1518
1492
}
1519
1493
1520
1494
case * sema.ReferenceType :
1521
- // Case (3): target type is non-optional, actual value is optional.
1522
- if someValue , ok := value .(* SomeValue ); ok {
1523
- locationRange := LocationRange {
1524
- Location : interpreter .Location ,
1525
- HasPosition : hasPosition ,
1495
+
1496
+ switch value := value .(type ) {
1497
+ case * SomeValue :
1498
+ // Case (3.a): target type is non-optional, actual value is optional.
1499
+ innerValue := value .InnerValue (interpreter , locationRange )
1500
+
1501
+ return interpreter .createReference (typ , innerValue , locationRange , false )
1502
+
1503
+ case NilValue :
1504
+ // Case (3.b) value is nil.
1505
+ // Since the resulting type can NOT accommodate a nil (non-optional reference), error-out.
1506
+ panic (NonOptionalReferenceToNilError {
1507
+ ReferenceType : typ ,
1508
+ LocationRange : locationRange ,
1509
+ })
1510
+
1511
+ case ReferenceValue :
1512
+ if isImplicit {
1513
+ // During implicit reference creation (e.g: member/index access on a reference),
1514
+ // if the value is already a reference then return the same reference.
1515
+ // However, we need to make sure that this reference is actually a subtype of the resultType,
1516
+ // since the checker may not be aware that we are "short-circuiting" in this case.
1517
+ // Additionally, it is only safe to "compress" reference types like this when the desired
1518
+ // result reference type is unauthorized
1519
+ staticType := value .StaticType (interpreter )
1520
+ if typ .Authorization != sema .UnauthorizedAccess || ! interpreter .IsSubTypeOfSemaType (staticType , typ ) {
1521
+ panic (InvalidMemberReferenceError {
1522
+ ExpectedType : typ ,
1523
+ ActualType : interpreter .MustConvertStaticToSemaType (staticType ),
1524
+ LocationRange : locationRange ,
1525
+ })
1526
+ }
1527
+
1528
+ return value
1526
1529
}
1527
- innerValue := someValue .InnerValue (interpreter , locationRange )
1528
1530
1529
- return interpreter . createReference ( typ , innerValue , hasPosition )
1531
+ // break
1530
1532
}
1531
1533
1532
1534
// Case (4): target type is non-optional, actual value is also non-optional.
1533
- return interpreter .newEphemeralReference (value , typ , hasPosition )
1535
+ return interpreter .newEphemeralReference (value , typ , locationRange )
1534
1536
1535
1537
default :
1536
1538
panic (errors .NewUnreachableError ())
@@ -1540,17 +1542,12 @@ func (interpreter *Interpreter) createReference(
1540
1542
func (interpreter * Interpreter ) newEphemeralReference (
1541
1543
value Value ,
1542
1544
typ * sema.ReferenceType ,
1543
- hasPosition ast. HasPosition ,
1545
+ locationRange LocationRange ,
1544
1546
) * EphemeralReferenceValue {
1545
1547
// If we are currently interpreting a function that was declared with mapped entitlement access, any appearances
1546
1548
// of that mapped access in the body of the function should be replaced with the computed output of the map
1547
1549
auth := ConvertSemaAccessToStaticAuthorization (interpreter , typ .Authorization )
1548
1550
1549
- locationRange := LocationRange {
1550
- Location : interpreter .Location ,
1551
- HasPosition : hasPosition ,
1552
- }
1553
-
1554
1551
return NewEphemeralReferenceValue (
1555
1552
interpreter ,
1556
1553
auth ,
0 commit comments