Skip to content

Commit fdcbc96

Browse files
committed
Implement casting rules for wildcard generics
1 parent 1c3a8d2 commit fdcbc96

File tree

20 files changed

+204
-29
lines changed

20 files changed

+204
-29
lines changed

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedEval.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ public CastedExpression of(Expression value) {
6363
if (implicitCast.isPresent())
6464
return CastedExpression.implicit(implicitCast.get());
6565

66-
Optional<Expression> castedImplicitlyTo = value.type.castImplicitTo(position, value, type);
66+
Optional<Expression> castedImplicitlyTo = value.type.castImplicitTo(position, value, type, compiler.getAvailableExpansions());
6767
if (castedImplicitlyTo.isPresent())
6868
return CastedExpression.implicit(castedImplicitlyTo.get());
6969

70-
Optional<Expression> castedImplicitlyFrom = type.castImplicitFrom(position, value);
70+
Optional<Expression> castedImplicitlyFrom = type.castImplicitFrom(position, value, compiler.getAvailableExpansions());
7171
if (castedImplicitlyFrom.isPresent())
7272
return CastedExpression.implicit(castedImplicitlyFrom.get());
7373

@@ -86,7 +86,7 @@ public CastedExpression of(Expression value) {
8686
return result;
8787
}
8888

89-
if (this.type.extendsOrImplements(value.type, compiler.getAvailableExpansions()))
89+
if (value.type.extendsOrImplements(type, compiler.getAvailableExpansions()))
9090
return CastedExpression.implicit(new SupertypeCastExpression(position, value, type));
9191

9292
if (explicit) {

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ResolvedType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.openzen.zenscript.codemodel.expression.CallArguments;
77
import org.openzen.zenscript.codemodel.expression.Expression;
88
import org.openzen.zenscript.codemodel.expression.switchvalue.SwitchValue;
9+
import org.openzen.zenscript.codemodel.identifiers.ExpansionSymbol;
910
import org.openzen.zenscript.codemodel.identifiers.MethodSymbol;
1011
import org.openzen.zenscript.codemodel.identifiers.TypeSymbol;
1112
import org.openzen.zenscript.codemodel.identifiers.instances.IteratorInstance;
@@ -87,7 +88,7 @@ default boolean canCastImplicitlyTo(TypeID target) {
8788

8889
List<MethodSymbol> getInterfaceMethodsToImplement();
8990

90-
boolean extendsOrImplements(TypeID type);
91+
boolean extendsOrImplements(TypeID type, List<ExpansionSymbol> expansions);
9192

9293
interface SwitchMember {
9394
SwitchValue toSwitchValue(List<CompilingVariable> bindings);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/ExpressionVisitor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public interface ExpressionVisitor<T> {
5959

6060
T visitFunction(FunctionExpression expression);
6161

62+
T visitGenericCast(GenericWildcardCastExpression expression);
63+
6264
T visitGetField(GetFieldExpression expression);
6365

6466
T visitGetFunctionParameter(GetFunctionParameterExpression expression);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/ExpressionVisitorWithContext.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public interface ExpressionVisitorWithContext<C, R> {
5959

6060
R visitFunction(C context, FunctionExpression expression);
6161

62+
R visitGenericCast(C context, GenericWildcardCastExpression expression);
63+
6264
R visitGetField(C context, GetFieldExpression expression);
6365

6466
R visitGetFunctionParameter(C context, GetFunctionParameterExpression expression);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.openzen.zenscript.codemodel.expression;
2+
3+
import org.openzen.zencode.shared.CodePosition;
4+
import org.openzen.zenscript.codemodel.type.TypeID;
5+
6+
public class GenericWildcardCastExpression extends Expression {
7+
public final Expression value;
8+
9+
public GenericWildcardCastExpression(CodePosition position, Expression value, TypeID type) {
10+
super(position, type, value.thrownType);
11+
12+
this.value = value;
13+
}
14+
15+
@Override
16+
public <T> T accept(ExpressionVisitor<T> visitor) {
17+
return visitor.visitGenericCast(this);
18+
}
19+
20+
@Override
21+
public <C, R> R accept(C context, ExpressionVisitorWithContext<C, R> visitor) {
22+
return visitor.visitGenericCast(context, this);
23+
}
24+
25+
@Override
26+
public Expression transform(ExpressionTransformer transformer) {
27+
Expression transformedValue = transformer.transform(value);
28+
return transformedValue == value ? this : new GenericWildcardCastExpression(position, transformedValue, type);
29+
}
30+
}

CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/DefinitionTypeID.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package org.openzen.zenscript.codemodel.type;
22

3+
import org.openzen.zencode.shared.CodePosition;
34
import org.openzen.zenscript.codemodel.GenericMapper;
45
import org.openzen.zenscript.codemodel.compilation.ResolvingType;
56
import org.openzen.zenscript.codemodel.definition.EnumDefinition;
67
import org.openzen.zenscript.codemodel.definition.StructDefinition;
78
import org.openzen.zenscript.codemodel.definition.VariantDefinition;
9+
import org.openzen.zenscript.codemodel.expression.Expression;
10+
import org.openzen.zenscript.codemodel.expression.GenericWildcardCastExpression;
811
import org.openzen.zenscript.codemodel.generic.TypeParameter;
12+
import org.openzen.zenscript.codemodel.identifiers.ExpansionSymbol;
913
import org.openzen.zenscript.codemodel.identifiers.TypeSymbol;
1014

1115
import java.util.*;
@@ -100,6 +104,50 @@ public TypeID getSuperType() {
100104
return definition.getSupertype(typeArguments).orElse(null);
101105
}
102106

107+
@Override
108+
public Optional<Expression> castImplicitTo(
109+
CodePosition position,
110+
Expression value,
111+
TypeID other,
112+
List<ExpansionSymbol> expansions) {
113+
if (other instanceof DefinitionTypeID) {
114+
DefinitionTypeID otherType = (DefinitionTypeID) other;
115+
if (definition.equals(otherType.definition)) {
116+
if (typeArguments.length != otherType.typeArguments.length)
117+
throw new IllegalArgumentException("Type arguments do not match: " + this + " -> " + other);
118+
119+
for (int i = 0; i < typeArguments.length; i++) {
120+
if (!otherType.typeArguments[i].canCastGenericFrom(typeArguments[i], expansions))
121+
return Optional.empty();
122+
}
123+
124+
return Optional.of(new GenericWildcardCastExpression(position, value, otherType));
125+
}
126+
}
127+
128+
return Optional.empty();
129+
}
130+
131+
@Override
132+
public boolean isEquivalentTo(TypeID other, List<ExpansionSymbol> expansions) {
133+
if (other instanceof DefinitionTypeID) {
134+
DefinitionTypeID otherType = (DefinitionTypeID) other;
135+
if (definition.equals(otherType.definition)) {
136+
if (typeArguments.length != otherType.typeArguments.length)
137+
throw new IllegalArgumentException("Type arguments do not match: " + this + " -> " + other);
138+
139+
for (int i = 0; i < typeArguments.length; i++) {
140+
if (!otherType.typeArguments[i].canCastGenericFrom(typeArguments[i], expansions))
141+
return TypeID.super.isEquivalentTo(other, expansions);
142+
}
143+
144+
return true;
145+
}
146+
}
147+
148+
return TypeID.super.isEquivalentTo(other, expansions);
149+
}
150+
103151
@Override
104152
public <R> R accept(TypeVisitor<R> visitor) {
105153
return visitor.visitDefinition(this);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/TypeID.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,22 @@ default InvalidTypeID asInvalid() {
9494
return new InvalidTypeID(CodePosition.UNKNOWN, CompileErrors.invalidType());
9595
}
9696

97-
default Optional<Expression> castImplicitTo(CodePosition position, Expression value, TypeID toType) {
97+
default Optional<Expression> castImplicitTo(
98+
CodePosition position,
99+
Expression value,
100+
TypeID toType,
101+
List<ExpansionSymbol> expansions) {
98102
return Optional.empty();
99103
}
100104

101-
default Optional<Expression> castImplicitFrom(CodePosition position, Expression value) {
105+
default Optional<Expression> castImplicitFrom(CodePosition position, Expression value, List<ExpansionSymbol> expansions) {
102106
return Optional.empty();
103107
}
104108

109+
default boolean canCastGenericFrom(TypeID fromType, List<ExpansionSymbol> expansions) {
110+
return false;
111+
}
112+
105113
default Optional<OptionalTypeID> asOptional() {
106114
return Optional.empty();
107115
}
@@ -141,7 +149,18 @@ default ResolvedType resolveWithoutExpansions() {
141149
}
142150

143151
default boolean extendsOrImplements(TypeID type, List<ExpansionSymbol> expansions) {
144-
return this.resolve().withExpansions(expansions).extendsOrImplements(type);
152+
return this.resolve().withExpansions(expansions).extendsOrImplements(type, expansions);
153+
}
154+
155+
/**
156+
* Similar to equals, but takes into account wildcard generics.
157+
*
158+
* @param type
159+
* @param expansions
160+
* @return
161+
*/
162+
default boolean isEquivalentTo(TypeID type, List<ExpansionSymbol> expansions) {
163+
return this.equals(type);
145164
}
146165

147166
/**

CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/WildcardInTypeID.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
package org.openzen.zenscript.codemodel.type;
22

3+
import org.openzen.zencode.shared.CodePosition;
34
import org.openzen.zenscript.codemodel.GenericMapper;
45
import org.openzen.zenscript.codemodel.compilation.ResolvingType;
6+
import org.openzen.zenscript.codemodel.expression.Expression;
7+
import org.openzen.zenscript.codemodel.expression.GenericWildcardCastExpression;
58
import org.openzen.zenscript.codemodel.generic.TypeParameter;
9+
import org.openzen.zenscript.codemodel.identifiers.ExpansionSymbol;
610
import org.openzen.zenscript.codemodel.type.member.MemberSet;
711

12+
import java.util.Collections;
813
import java.util.List;
914
import java.util.Objects;
15+
import java.util.Optional;
1016

1117
/**
1218
* Represents a wildcard type with a lower bound. (e.g. ? super Number)
@@ -34,6 +40,17 @@ public void extractTypeParameters(List<TypeParameter> typeParameters) {
3440
lowerBound.extractTypeParameters(typeParameters);
3541
}
3642

43+
@Override
44+
public Optional<Expression> castImplicitFrom(CodePosition position, Expression value, List<ExpansionSymbol> expansions) {
45+
return lowerBound.castImplicitTo(position, value, lowerBound, expansions)
46+
.map(v -> new GenericWildcardCastExpression(position, v, this));
47+
}
48+
49+
@Override
50+
public boolean canCastGenericFrom(TypeID fromType, List<ExpansionSymbol> expansions) {
51+
return lowerBound.extendsOrImplements(fromType, expansions);
52+
}
53+
3754
@Override
3855
public <R> R accept(TypeVisitor<R> visitor) {
3956
return visitor.visitWildcardIn(this);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/WildcardOutTypeID.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package org.openzen.zenscript.codemodel.type;
22

3+
import org.openzen.zencode.shared.CodePosition;
34
import org.openzen.zenscript.codemodel.GenericMapper;
45
import org.openzen.zenscript.codemodel.compilation.ResolvingType;
6+
import org.openzen.zenscript.codemodel.expression.Expression;
7+
import org.openzen.zenscript.codemodel.expression.GenericWildcardCastExpression;
58
import org.openzen.zenscript.codemodel.generic.TypeParameter;
9+
import org.openzen.zenscript.codemodel.identifiers.ExpansionSymbol;
610

11+
import java.util.Collections;
712
import java.util.List;
813
import java.util.Objects;
14+
import java.util.Optional;
915

1016
/**
1117
* Represents a wildcard type with an upper bound. (eg. ? extends Number)
@@ -36,6 +42,21 @@ public void extractTypeParameters(List<TypeParameter> typeParameters) {
3642
upperBound.extractTypeParameters(typeParameters);
3743
}
3844

45+
@Override
46+
public Optional<Expression> castImplicitTo(
47+
CodePosition position,
48+
Expression value,
49+
TypeID toType,
50+
List<ExpansionSymbol> expansions) {
51+
return upperBound.castImplicitTo(position, value, toType, expansions)
52+
.map(v -> new GenericWildcardCastExpression(position, v, toType));
53+
}
54+
55+
@Override
56+
public boolean canCastGenericFrom(TypeID toType, List<ExpansionSymbol> expansions) {
57+
return toType.extendsOrImplements(upperBound, expansions);
58+
}
59+
3960
@Override
4061
public <R> R accept(TypeVisitor<R> visitor) {
4162
return visitor.visitWildcardOut(this);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/member/ExpandedResolvedType.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ public List<MethodSymbol> getInterfaceMethodsToImplement() {
182182
}
183183

184184
@Override
185-
public boolean extendsOrImplements(TypeID type) {
186-
return base.extendsOrImplements(type)
187-
|| expansions.stream().anyMatch(expansion -> expansion.extendsOrImplements(type));
185+
public boolean extendsOrImplements(TypeID type, List<ExpansionSymbol> allExpansions) {
186+
return base.extendsOrImplements(type, allExpansions)
187+
|| expansions.stream().anyMatch(expansion -> expansion.extendsOrImplements(type, allExpansions));
188188
}
189189

190190
@Override

0 commit comments

Comments
 (0)