protected override TypeVariableReference ComputeTypeToUnifyWith(VariableReference inputFacadeVariable, out bool setExpectedMutable) { setExpectedMutable = false; TypeVariableReference other = inputFacadeVariable.TypeVariableReference; TypeVariableReference u, l; bool otherIsMutableReference; bool otherIsReference = TypeVariableSet.TryDecomposeReferenceType(other, out u, out l, out otherIsMutableReference); TypeVariableReference underlyingType = otherIsReference ? u : other; NIType literalType; bool underlyingTypeIsLiteral = TypeVariableSet.TryGetLiteralType(underlyingType, out literalType); bool inputCoercesToStringSlice = underlyingTypeIsLiteral && (literalType == PFTypes.String || literalType == DataTypes.StringSliceType); bool needsBorrow = !otherIsReference || !underlyingTypeIsLiteral || literalType != DataTypes.StringSliceType; TypeVariableReference lifetimeType = otherIsReference ? l : TypeVariableSet.CreateReferenceToLifetimeType(_group.BorrowLifetime); if (needsBorrow) { _stringToSliceNeeded = true; _group.SetBorrowRequired(false); } // If the input is allowed to coerce to a str, we can unify with str; // otherwise, unify with the underlying type to get a type mismatch. TypeVariableReference toUnifyUnderlyingType = inputCoercesToStringSlice ? TypeVariableSet.CreateReferenceToLiteralType(DataTypes.StringSliceType) : underlyingType; return(TypeVariableSet.CreateReferenceToReferenceType( false, toUnifyUnderlyingType, lifetimeType)); }
protected override TypeVariableReference ComputeTypeToUnifyWith(VariableReference inputFacadeVariable, out bool setExpectedMutable) { TypeVariableReference other = inputFacadeVariable.TypeVariableReference; TypeVariableReference u, otherReferenceLifetime; bool otherIsMutableReference; bool otherIsReference = TypeVariableSet.TryDecomposeReferenceType(other, out u, out otherReferenceLifetime, out otherIsMutableReference); TypeVariableReference underlyingType = otherIsReference ? u : other; bool mutable = otherIsReference ? otherIsMutableReference : inputFacadeVariable.Mutable; TypeVariableReference typeToUnifyWith = default(TypeVariableReference); setExpectedMutable = false; switch (_mutability) { case InputReferenceMutability.RequireMutable: { TypeVariableReference lifetimeType; if (!otherIsReference) { _group.SetBorrowRequired(true); lifetimeType = TypeVariableSet.CreateReferenceToLifetimeType(_group.BorrowLifetime); } else { lifetimeType = otherReferenceLifetime; } typeToUnifyWith = TypeVariableSet.CreateReferenceToReferenceType(true, underlyingType, lifetimeType); setExpectedMutable = !mutable; break; } case InputReferenceMutability.AllowImmutable: { bool needsBorrow = !(otherIsReference && !otherIsMutableReference); TypeVariableReference lifetimeType; if (needsBorrow) { lifetimeType = TypeVariableSet.CreateReferenceToLifetimeType(_group.BorrowLifetime); _group.SetBorrowRequired(false); } else { lifetimeType = otherReferenceLifetime; } typeToUnifyWith = TypeVariableSet.CreateReferenceToReferenceType(false, underlyingType, lifetimeType); break; } case InputReferenceMutability.Polymorphic: { TypeVariableReference lifetimeType; if (!otherIsReference) { _group.SetBorrowRequired(false /* TODO depends on current state and input mutability */); lifetimeType = TypeVariableSet.CreateReferenceToLifetimeType(_group.BorrowLifetime); } else { // TODO: if TrueVariable.TypeVariableReference is already known to be immutable and // wire reference is mutable, then we need a borrow lifetimeType = otherReferenceLifetime; } typeToUnifyWith = TypeVariableSet.CreateReferenceToReferenceType(mutable, underlyingType, lifetimeType); break; } } return(typeToUnifyWith); }