/** @see jaskell.compiler.JaskellVisitor#visit(ConstructorPattern) */ public Object visit(ConstructorPattern a) { String cname = a.getConstructor().getName(); /* retrieve parameter types of constructor */ ConstructorDefinition ctor = (ConstructorDefinition) a.getConstructor().lookup(cname); if (ctor == null) throw new TypeError("Undefined constructor pattern " + a); /* type of data constructed by constructor */ TypeInstantiator ti = new TypeInstantiator(ctor.getDataType()); Type rtype = ti.instance(); Map map = ti.getMap(); TypeSubstitution ts = new TypeSubstitution(map); Iterator ittypes = ctor.getParameters().iterator(); /* retrieve type of patterns */ Iterator it = a.getSubPatterns(); while (it.hasNext()) { try { Pattern p = (Pattern) it.next(); Type actual = TypeFactory.freshBinding(); Type formal = ts.substitute((Type) ittypes.next()); /* unify both types */ p.setType(tu.unify(formal, actual, typeVariablesMap)); } catch (NoSuchElementException nex) { throw new TypeError("Wrong number of arguments to pattern " + a); } } a.setType(rtype); return a.getType(); }
@Test public void parametrizedTypeType_methods_tests() { JavaSymbol.PackageJavaSymbol packageSymbol = new JavaSymbol.PackageJavaSymbol("org.foo.bar", null); JavaSymbol.TypeJavaSymbol typeSymbol = new JavaSymbol.TypeJavaSymbol(Flags.PUBLIC, "MyType", packageSymbol); JavaSymbol.TypeVariableJavaSymbol typeVariableSymbol = new JavaSymbol.TypeVariableJavaSymbol("E", typeSymbol); ClassJavaType classType = (ClassJavaType) typeSymbol.type; TypeVariableJavaType typeVariableType = (TypeVariableJavaType) typeVariableSymbol.type; TypeSubstitution typeSubstitution = new TypeSubstitution(); typeSubstitution.add(typeVariableType, classType); ParametrizedTypeJavaType ptt = new ParametrizedTypeJavaType(typeSymbol, typeSubstitution); assertThat(ptt.substitution(typeVariableType)).isEqualTo(classType); assertThat( ptt.substitution( new TypeVariableJavaType(new JavaSymbol.TypeVariableJavaSymbol("F", typeSymbol)))) .isNull(); assertThat(ptt.typeParameters()).hasSize(1); assertThat(ptt.typeParameters()).contains(typeVariableType); ptt = new ParametrizedTypeJavaType(typeSymbol, null); assertThat(ptt.substitution(typeVariableType)).isNull(); assertThat(ptt.typeParameters()).isEmpty(); assertThat(ptt.isClass()).isTrue(); assertThat(ptt.isParameterized()).isTrue(); assertThat(ptt.rawType.isClass()).isTrue(); assertThat(ptt.rawType.isParameterized()).isFalse(); }
private JavaType handleTypeArguments( List<JavaType> typeParams, JavaType type, JavaSymbol.MethodJavaSymbol methodSymbol) { if (!typeParams.isEmpty() && methodSymbol.typeVariableTypes.size() == typeParams.size()) { TypeSubstitution typeSubstitution = new TypeSubstitution(); int i = 0; for (JavaType.TypeVariableJavaType typeVariableType : methodSymbol.typeVariableTypes) { typeSubstitution.add(typeVariableType, typeParams.get(i)); i++; } return substituteTypeParameter(type, typeSubstitution); } return type; }
/** @see jaskell.compiler.JaskellVisitor#visit(Application) */ public Object visit(Application a) { try { /* get type of function */ Expression fun = a.getFunction(); /* get type deduced from arguments */ LinkedList l = new LinkedList(); Iterator it = a.getArgs().iterator(); while (it.hasNext()) { Expression e = (Expression) it.next(); l.add((Type) e.visit(this)); } Type vt = TypeFactory.freshBinding(); Type ft = Types.fun(l, vt); log.finer("TypeChecker => In application " + a + ", type is " + ft); /* apply substitution on both types */ ft = subst.substitute(ft); /* try to unify function type and constructed types */ Type t = (Type) fun.visit(this); log.finer("In application, function " + fun + " :: " + t); t = subst.substitute(t); log.finer("In application, trying to unify function type " + t + " with body " + ft); /* * TODO : problem with unification of constrained types */ TypeApplication uni = (TypeApplication) tu.unify(t, ft, typeVariablesMap); /* sets type of functional expression - this allows * polymorphic functions to receive several types * in the same code */ // fun.setType(uni); /* apply arguments type to compute return type */ log.finer("Done unify application :" + uni); it = PrimitiveType.functionIterator(uni); Iterator it2 = l.iterator(); TypeApplication ut = uni; while (it2.hasNext()) { /* type of argument */ Type at = (Type) it2.next(); ut = (TypeApplication) it.next(); /* try unification */ tu.unify(((TypeApplication) ut.getDomain()).getRange(), at, new HashMap(typeVariablesMap)); } ft = subst.substitute(ft); fun.setType(ft); log.finer("Setting type of functional element [" + fun + "] to :" + ft); a.setType(ut.getRange()); return ut.getRange(); } catch (TypeError te) { if (te.getLineCol() == null) te.setLineCol(a.getTag("source")); throw te; } }
@Nullable public TypeProjection substitute(@NotNull TypeProjection typeProjection) { TypeProjection substitutedTypeProjection = substituteWithoutApproximation(typeProjection); if (!substitution.approximateCapturedTypes()) { return substitutedTypeProjection; } return CapturedTypeApproximationKt.approximateCapturedTypesIfNecessary( substitutedTypeProjection); }
@Override public void visitEnd() { if (!typeArguments.isEmpty()) { JavaSymbol.TypeJavaSymbol readSymbol = typeRead.symbol; readSymbol.complete(); // Mismatch between type variable and type arguments means we are lacking some pieces of // bytecode to resolve substitution properly. if (typeArguments.size() == readSymbol.typeVariableTypes.size()) { TypeSubstitution substitution = new TypeSubstitution(); int i = 0; for (JavaType typeArgument : typeArguments) { substitution.add(readSymbol.typeVariableTypes.get(i), typeArgument); i++; } typeRead = parametrizedTypeCache.getParametrizedTypeType(readSymbol, substitution); } } }
private JavaType substituteTypeParameter(JavaType type, TypeSubstitution substitution) { JavaType substitutedType = substitution.substitutedType(type); if (substitutedType != null) { return substitutedType; } if (type instanceof JavaType.ParametrizedTypeJavaType) { JavaType.ParametrizedTypeJavaType ptt = (JavaType.ParametrizedTypeJavaType) type; TypeSubstitution newSubstitution = new TypeSubstitution(); for (Map.Entry<JavaType.TypeVariableJavaType, JavaType> entry : ptt.typeSubstitution.substitutionEntries()) { newSubstitution.add( entry.getKey(), substituteTypeParameter(entry.getValue(), substitution)); } return parametrizedTypeCache.getParametrizedTypeType( ptt.rawType.getSymbol(), newSubstitution); } return type; }
@Test public void erasure_of_type_variable() { JavaSymbol.TypeJavaSymbol typeSymbol = new JavaSymbol.TypeJavaSymbol( Flags.PUBLIC, "MyType", new JavaSymbol.PackageJavaSymbol("org.foo.bar", null)); TypeSubstitution typeSubstitution = new TypeSubstitution(); typeSubstitution.add( (TypeVariableJavaType) new JavaSymbol.TypeVariableJavaSymbol("T", typeSymbol).type, typeSymbol.type); ParametrizedTypeJavaType parametrizedType = new ParametrizedTypeJavaType(typeSymbol, typeSubstitution); TypeVariableJavaType typeVariableType = (TypeVariableJavaType) new JavaSymbol.TypeVariableJavaSymbol("X", typeSymbol).type; typeVariableType.bounds = ImmutableList.<JavaType>of(parametrizedType); assertThat(typeVariableType.erasure()).isNotEqualTo(parametrizedType); assertThat(typeVariableType.erasure()).isEqualTo(parametrizedType.erasure()); }
/** @see jaskell.compiler.JaskellVisitor#visit(Abstraction) */ public Object visit(Abstraction a) { try { Type t = a.getType(); if (t != null) return subst.substitute(t); log.finest("Visiting abstraction : " + a); Expression body = a.getBody(); /* duplicate bindings map to assign types to variables */ pushContext(a.getBindings()); /* create fresh type variables as type for each bound * variable */ Iterator it = namesMap.values().iterator(); LinkedList tl = new LinkedList(); while (it.hasNext()) { LocalBinding name = (LocalBinding) it.next(); Type vt = TypeFactory.freshBinding(); name.setType(vt); tl.add(vt); } Type tv = TypeFactory.freshBinding(); /* create type with all variables for function */ Type ft = Types.fun(tl, tv); log.finer("In abstraction, setting type to " + ft); a.setType(ft); /* analyze body */ Type bt = (Type) body.visit(this); /* unify return type of function with type of body */ Type ret = tu.unify(PrimitiveType.getReturnType(ft), bt, typeVariablesMap); TyvarSubstitution tys = new TyvarSubstitution(typeVariablesMap); tys.visit(a); log.finer("Done abstraction, setting type from " + ft + " to " + a.getType()); popContext(); return a.getType(); } catch (TypeError te) { if (te.getLineCol() == null) te.setLineCol(a.getTag("source")); throw te; } }
public boolean isEmpty() { return substitution.isEmpty(); }
@NotNull private TypeProjection unsafeSubstitute( @NotNull TypeProjection originalProjection, int recursionDepth) throws SubstitutionException { assertRecursionDepth(recursionDepth, originalProjection, substitution); if (originalProjection.isStarProjection()) return originalProjection; // The type is within the substitution range, i.e. T or T? JetType type = originalProjection.getType(); TypeProjection replacement = substitution.get(type); Variance originalProjectionKind = originalProjection.getProjectionKind(); if (replacement == null && FlexibleTypesKt.isFlexible(type) && !TypeCapabilitiesKt.isCustomTypeVariable(type)) { Flexibility flexibility = FlexibleTypesKt.flexibility(type); TypeProjection substitutedLower = unsafeSubstitute( new TypeProjectionImpl(originalProjectionKind, flexibility.getLowerBound()), recursionDepth + 1); TypeProjection substitutedUpper = unsafeSubstitute( new TypeProjectionImpl(originalProjectionKind, flexibility.getUpperBound()), recursionDepth + 1); Variance substitutedProjectionKind = substitutedLower.getProjectionKind(); assert (substitutedProjectionKind == substitutedUpper.getProjectionKind()) && originalProjectionKind == Variance.INVARIANT || originalProjectionKind == substitutedProjectionKind : "Unexpected substituted projection kind: " + substitutedProjectionKind + "; original: " + originalProjectionKind; JetType substitutedFlexibleType = DelegatingFlexibleType.create( substitutedLower.getType(), substitutedUpper.getType(), flexibility.getExtraCapabilities()); return new TypeProjectionImpl(substitutedProjectionKind, substitutedFlexibleType); } if (KotlinBuiltIns.isNothing(type) || type.isError()) return originalProjection; if (replacement != null) { VarianceConflictType varianceConflict = conflictType(originalProjectionKind, replacement.getProjectionKind()); // Captured type might be substituted in an opposite projection: // out 'Captured (in Int)' = out Int // in 'Captured (out Int)' = in Int boolean allowVarianceConflict = CapturedTypeConstructorKt.isCaptured(type); if (!allowVarianceConflict) { //noinspection EnumSwitchStatementWhichMissesCases switch (varianceConflict) { case OUT_IN_IN_POSITION: throw new SubstitutionException("Out-projection in in-position"); case IN_IN_OUT_POSITION: // todo use the right type parameter variance and upper bound return new TypeProjectionImpl( Variance.OUT_VARIANCE, type.getConstructor().getBuiltIns().getNullableAnyType()); } } JetType substitutedType; CustomTypeVariable typeVariable = TypeCapabilitiesKt.getCustomTypeVariable(type); if (replacement.isStarProjection()) { return replacement; } else if (typeVariable != null) { substitutedType = typeVariable.substitutionResult(replacement.getType()); } else { // this is a simple type T or T?: if it's T, we should just take replacement, if T? - we // make replacement nullable substitutedType = TypeUtils.makeNullableIfNeeded(replacement.getType(), type.isMarkedNullable()); } // substitutionType.annotations = replacement.annotations ++ type.annotations if (!type.getAnnotations().isEmpty()) { Annotations typeAnnotations = filterOutUnsafeVariance(type.getAnnotations()); substitutedType = TypeUtilsKt.replaceAnnotations( substitutedType, new CompositeAnnotations(substitutedType.getAnnotations(), typeAnnotations)); } Variance resultingProjectionKind = varianceConflict == VarianceConflictType.NO_CONFLICT ? combine(originalProjectionKind, replacement.getProjectionKind()) : originalProjectionKind; return new TypeProjectionImpl(resultingProjectionKind, substitutedType); } // The type is not within the substitution range, i.e. Foo, Bar<T> etc. return substituteCompoundType(originalProjection, recursionDepth); }