@@ -443,15 +443,22 @@ public Term constructArrayAccessLVal(Expr.ArrayAccess expr, Term source, Term in
443443
444444 @ Override
445445 public Term constructDereferenceLVal (Expr .Dereference expr , Term operand ) {
446- return new PropertyAccess (operand , "$ref" );
446+ Type .Reference type = expr .getOperand ().getType ().as (Type .Reference .class );
447+ //
448+ if (isBoxedType (type )) {
449+ return new PropertyAccess (operand , "$ref" );
450+ } else {
451+ return operand ;
452+ }
447453 }
448454
449455 @ Override
450456 public Term constructFieldDereferenceLVal (Expr .FieldDereference expr , Term operand ) {
451- Type type = expr .getOperand ().getType ();
457+ Type . Reference type = expr .getOperand ().getType (). as ( Type . Reference . class );
452458 //
453- if (!isUnknownReference (type )) {
454- // Known types are explicitly wrapped, whilst unknown types are not.
459+ if (isBoxedType (type )) {
460+ // Immutable types must be explicitly boxed since they cannot be updated in
461+ // place.
455462 operand = new PropertyAccess (operand , "$ref" );
456463 }
457464 return new PropertyAccess (operand , expr .getField ().get ());
@@ -583,14 +590,22 @@ public Term constructConstant(Expr.Constant expr) {
583590
584591 @ Override
585592 public Term constructDereference (Expr .Dereference expr , Term operand ) {
586- return new PropertyAccess (operand , "$ref" );
593+ Type .Reference type = expr .getOperand ().getType ().as (Type .Reference .class );
594+ if (isBoxedType (type )) {
595+ // Immutable types must be explicitly boxed since they cannot be updated in
596+ // place.
597+ return new PropertyAccess (operand , "$ref" );
598+ } else {
599+ return operand ;
600+ }
587601 }
588602
589603 @ Override
590604 public Term constructFieldDereference (Expr .FieldDereference expr , Term operand ) {
591- Type type = expr .getOperand ().getType ();
592- if (!isUnknownReference (type )) {
593- // Known types are explicitly wrapped, whilst unknown types are not.
605+ Type .Reference type = expr .getOperand ().getType ().as (Type .Reference .class );
606+ if (isBoxedType (type )) {
607+ // Immutable types must be explicitly boxed since they cannot be updated in
608+ // place.
594609 operand = new PropertyAccess (operand , "$ref" );
595610 }
596611 return new PropertyAccess (operand , expr .getField ().get ());
@@ -736,8 +751,15 @@ public Term constructLambdaAccess(Expr.LambdaAccess expr) {
736751
737752 @ Override
738753 public Term constructNew (Expr .New expr , Term operand ) {
739- // known types must be converted into references
740- return new Operator (Kind .NEW ,WY_REF (operand ));
754+ Type .Reference type = expr .getType ().as (Type .Reference .class );
755+ //
756+ if (isBoxedType (type )) {
757+ // Immutable types must be boxed as they cannot be updated in place. All other
758+ // types don't need to be boxed.
759+ return new Operator (Kind .NEW ,WY_REF (operand ));
760+ } else {
761+ return operand ;
762+ }
741763 }
742764
743765 @ Override
@@ -1991,6 +2013,27 @@ private boolean areStrictSubtypes(Type type, List<? extends Type> types) {
19912013 return true ;
19922014 }
19932015
2016+ /**
2017+ * Check whether a given type is immutable or not. An immutable type is one
2018+ * which needs to be boxed for a reference to it to be generated.
2019+ *
2020+ * @return
2021+ */
2022+ public boolean isBoxedType (Type .Reference type ) {
2023+ Type element = type .getElement ();
2024+ // Strip away nominal info
2025+ while (element instanceof Type .Nominal ) {
2026+ Type .Nominal n = (Type .Nominal ) element ;
2027+ element = n .getConcreteType ();
2028+ }
2029+ //
2030+ if (element instanceof Type .Record ) {
2031+ Type .Record r = (Type .Record ) element ;
2032+ return !r .isOpen ();
2033+ } else {
2034+ return true ;
2035+ }
2036+ }
19942037
19952038 /**
19962039 * Return true if the type in question can be copied directly. More
@@ -2028,19 +2071,6 @@ private boolean isCopyable(Type type) {
20282071 }
20292072 }
20302073
2031- private boolean isUnknownReference (Type type ) {
2032- if (type instanceof Type .Reference ) {
2033- Type .Reference t = (Type .Reference ) type ;
2034- return t .isUnknown ();
2035- } else if (type instanceof Type .Nominal ) {
2036- Type .Nominal t = (Type .Nominal ) type ;
2037- Decl .Type td = t .getLink ().getTarget ();
2038- return isUnknownReference (td .getType ());
2039- } else {
2040- return false ;
2041- }
2042- }
2043-
20442074 /**
20452075 * Check whether the given type has any subtypes other than that of the given
20462076 * kind. For example, <code>int|{int f}</code> has a subtype other than a record
0 commit comments