Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Commit

Permalink
implicit defaults for variant type parameters #4397
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinking committed May 12, 2015
1 parent bbf18d8 commit 3628de5
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import static com.redhat.ceylon.compiler.typechecker.tree.Util.getNativeBackend;
import static com.redhat.ceylon.compiler.typechecker.tree.Util.hasAnnotation;
import static com.redhat.ceylon.compiler.typechecker.tree.Util.name;
import static java.util.Collections.emptyList;
import static com.redhat.ceylon.model.typechecker.model.Util.getContainingClassOrInterface;
import static com.redhat.ceylon.model.typechecker.model.Util.getTypeArgumentMap;
import static com.redhat.ceylon.model.typechecker.model.Util.intersectionOfSupertypes;
import static com.redhat.ceylon.model.typechecker.model.Util.isInNativeContainer;
import static com.redhat.ceylon.model.typechecker.model.Util.isNativeNoImpl;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;

Expand Down Expand Up @@ -770,24 +770,53 @@ public void visit(Tree.TypeAliasDeclaration that) {
public void visit(Tree.TypeParameterDeclaration that) {
Tree.TypeSpecifier ts = that.getTypeSpecifier();
Tree.TypeVariance tv = that.getTypeVariance();
TypeParameter p = new TypeParameter();
final TypeParameter p = new TypeParameter();
defaultExtendedToAnything(p);
p.setDeclaration(declaration);
p.setDefaulted(ts!=null);
if (tv!=null) {
String v = tv.getText();
p.setCovariant("out".equals(v));
p.setContravariant("in".equals(v));
}
that.setDeclarationModel(p);
visitDeclaration(that, p);

super.visit(that);

ProducedType dta = null;
if (ts!=null) {
Tree.StaticType type = ts.getType();
if (type!=null) {
p.setDefaultTypeArgument(type.getTypeModel());
dta = type.getTypeModel();
}
}
else {
if (p.isCovariant()) {
dta = new LazyProducedType(unit) {
ProducedType get() {
ProducedType result =
intersectionOfSupertypes(p);
return result.containsTypeParameters() ?
null : result;
}
@Override
public Map<TypeParameter, ProducedType>
initTypeArguments() {
return get().getTypeArguments();
}
@Override
public TypeDeclaration initDeclaration() {
return get().getDeclaration();
}
};
}
else if (p.isContravariant()) {
dta = unit.getNothingDeclaration()
.getType();
}
}
p.setDefaultTypeArgument(dta);
p.setDefaulted(dta!=null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@ public class DefaultTypeArgVisitor extends Visitor {

@Override
public void visit(Tree.TypeParameterDeclaration that) {
TypeParameter tpd = that.getDeclarationModel();
ProducedType dta = tpd.getDefaultTypeArgument();
if (dta!=null) {
try {
if (dta.containsDeclaration(tpd.getDeclaration())) {
Tree.TypeSpecifier ts = that.getTypeSpecifier();
if (ts!=null) {
TypeParameter tpd = that.getDeclarationModel();
ProducedType dta = tpd.getDefaultTypeArgument();
if (dta!=null) {
try {
if (dta.containsDeclaration(tpd.getDeclaration())) {
tpd.setDefaultTypeArgument(null);
}
}
catch (RuntimeException re) {
ts.addError("undecidable default type argument");
tpd.setDefaultTypeArgument(null);
}
}
catch (RuntimeException re) {
that.getTypeSpecifier().addError("undecidable default type argument");
tpd.setDefaultTypeArgument(null);
}
}
super.visit(that);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2916,12 +2916,16 @@ private List<ProducedType> inferFunctionRefTypeArgs(
if (unit.isCallableType(paramType)) {
ProducedType template;
if (smte.getStaticMethodReferencePrimary()) {
template = producedType(unit.getTupleDeclaration(),
arg.getType(), arg.getType(),
unit.getType(unit.getEmptyDeclaration()));
ProducedType type = arg.getType();
ProducedType et =
unit.getType(unit.getEmptyDeclaration());
template =
producedType(unit.getTupleDeclaration(),
type, type, et);
}
else {
template = unit.getCallableTuple(arg.getFullType());
template =
unit.getCallableTuple(arg.getFullType());
}
ProducedType type =
unit.getCallableTuple(paramType);
Expand Down Expand Up @@ -6950,7 +6954,10 @@ private boolean explicitTypeArguments(Declaration dec, Tree.TypeArguments tal) {
if (tal!=null) {
//TODO: dupe of logic in TypeVisitor!!!!
List<Tree.Type> args = tal.getTypes();
for (int i = 0; i<args.size(); i++) {
for (int i = 0;
i<args.size() &&
i<params.size();
i++) {
Tree.Type t = args.get(i);
if (t instanceof Tree.StaticType) {
TypeParameter p = params.get(i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,10 @@ private void visitSimpleType(Tree.SimpleType that,
tal.setTypeModels(typeArgs);
//TODO: dupe of logic in ExpressionVisitor
List<Tree.Type> args = tal.getTypes();
for (int i = 0; i<args.size(); i++) {
for (int i = 0;
i<args.size() &&
i<params.size();
i++) {
Tree.Type t = args.get(i);
if (t instanceof Tree.StaticType) {
Tree.StaticType st =
Expand Down Expand Up @@ -1223,32 +1226,51 @@ public void visit(Tree.InterfaceDefinition that) {

@Override
public void visit(Tree.TypeParameterDeclaration that) {
TypeParameter tpd = that.getDeclarationModel();
tpd.setExtendedType(null);
tpd.getSatisfiedTypes().clear();
final TypeParameter p = that.getDeclarationModel();
p.setExtendedType(null);
p.getSatisfiedTypes().clear();
Class vd = unit.getAnythingDeclaration();
if (vd!=null) {
tpd.setExtendedType(vd.getType());
p.setExtendedType(vd.getType());
}

super.visit(that);

ProducedType dta = null;
Tree.TypeSpecifier ts = that.getTypeSpecifier();
if (ts!=null) {
Tree.StaticType type = ts.getType();
if (type!=null) {
ProducedType dta = type.getTypeModel();
dta = type.getTypeModel();
if (dta!=null &&
dta.containsDeclaration(tpd.getDeclaration())) {
type.addError("default type argument involves parameterized type");
dta.containsDeclaration(p.getDeclaration())) {
type.addError("default type argument involves parameterized type: '" +
dta.getProducedTypeName(unit) + "' involves '" +
p.getDeclaration().getName(unit) + "'");
dta = null;
}
/*else if (t.containsTypeParameters()) {
/*else if (dta.containsTypeParameters()) {
type.addError("default type argument involves type parameters: " +
t.getProducedTypeName());
dta.getProducedTypeName(unit));
dta = null;
}*/
else {
tpd.setDefaultTypeArgument(dta);
}
}
else {
if (p.isCovariant()) {
ProducedType result =
intersectionOfSupertypes(p);
if (!result.containsTypeParameters()) {
dta = result;
}
}
else if (p.isContravariant()) {
dta = unit.getNothingDeclaration()
.getType();
}
}
p.setDefaultTypeArgument(dta);

}

@Override
Expand All @@ -1264,10 +1286,11 @@ public void visit(Tree.TypeParameterList that) {
if (tpd!=null) {
TypeParameter tp =
tpd.getDeclarationModel();
if (tp.getDefaultTypeArgument()!=null) {
ProducedType dta =
tp.getDefaultTypeArgument();
if (dta!=null) {
params.add(tp);
if (tp.getDefaultTypeArgument()
.containsTypeParameters(params)) {
if (dta.containsTypeParameters(params)) {
tpd.getTypeSpecifier()
.addError("default type argument involves a type parameter not yet declared");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,23 +204,25 @@ static List<ProducedType> getTypeArguments(Tree.TypeArguments tas,
}
}
}
for (int i=typeArguments.size(); i<size; i++) {
TypeParameter tp = typeParameters.get(i);
ProducedType dta =
tp.getDefaultTypeArgument();
if (dta==null ||
//necessary to prevent stack overflow
//for illegal recursively-defined
//default type argument
dta.containsDeclaration(tp.getDeclaration())) {
break;
}
else {
ProducedType da =
dta.substitute(typeArgMap);
typeArguments.add(da);
typeArgMap.put(tp, da);
}
if (!(tas instanceof Tree.InferredTypeArguments)) {
for (int i=typeArguments.size(); i<size; i++) {
TypeParameter tp = typeParameters.get(i);
ProducedType dta =
tp.getDefaultTypeArgument();
if (dta==null ||
//necessary to prevent stack overflow
//for illegal recursively-defined
//default type argument
dta.containsDeclaration(tp.getDeclaration())) {
break;
}
else {
ProducedType da =
dta.substitute(typeArgMap);
typeArguments.add(da);
typeArgMap.put(tp, da);
}
}
}
return typeArguments;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import ceylon.language { Any=Anything }

interface Inv<T> {}
interface I1 => Iterable<String>;
interface I2<S> => Iterable<S>;
@error interface I3 => Iterable;
interface I3 => Iterable;
@error interface I4 => Inv;
class E1(String name, Integer i) => Entry<String,Integer>(name,i);
class E2<T>(String name, T t) given T satisfies Object => Entry<String,T>(name,t);
class E3<T>(T t, String s) given T satisfies Object => Entry<T,String>(t,s);
Expand Down
2 changes: 1 addition & 1 deletion typechecker/test/main/function/FunctionTypes.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void method() {
value temp = sqrt;
Float root(Float x) => temp(x);

@error Callable<Anything> reallyBroken(void foo()) {
Callable<Anything> reallyBroken(void foo()) {
/*@error*/ return foo;
}

Expand Down
6 changes: 6 additions & 0 deletions typechecker/test/main/metamodel/metamodel.ceylon
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import ceylon.language.meta.model {...}
import ceylon.language.meta.declaration {...}

interface List<Element>
satisfies {Element*} &
Correspondence<Integer,Element> {
defines(Integer i) => nothing;
}

void test<T>() {
@type:"ClassDeclaration"
value noParamsClass = `class NoParams`;
Expand Down
7 changes: 7 additions & 0 deletions typechecker/test/main/typing/DefaultTypeArgs.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,15 @@ class DefaultTypeArgs() {
@type:"Category<Object>" Category<> categoryWith0Args;
@type:"DefaultTypeArgs.Wraps<Anything>" Wraps<> wrapsWith0Args;

class Singleton<T>(T t) {}

@error String<>("");
@error Singleton<>(1);
@type:"DefaultTypeArgs.Wraps<Anything>" Wraps<>(1.0);

@type:"List<Anything>" List<> list1 = [1,2];
@type:"List<Anything>" List list2 = ["",""];
@type:"Comparable<Nothing>" Comparable<> comp1 = 1;
@type:"Comparable<Nothing>" Comparable comp2 = 1;

}
20 changes: 16 additions & 4 deletions typechecker/test/main/typing/Generics.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ class Generics() {
@error class Bad3<out T>() satisfies WithContravariant<T> {}
@error class Bad4<in T>() satisfies WithContravariant<Consumer<T>> {}

interface WithInvariant<X> {}

@error: "sealed interface"
interface SequenceSequence<out T, out X>
satisfies Sequence<T>
Expand Down Expand Up @@ -334,10 +336,20 @@ class Generics() {
@error Generics.Producer<Holder> ghp = Generics.Producer<Holder>();
@error Generics.Producer<Holder>? gohp = null;

@error object wc satisfies WithCovariant {}
@error object wch satisfies WithCovariant<Holder> {}
@error object gwc satisfies Generics.WithCovariant {}
@error object gwch satisfies Generics.WithCovariant<Holder> {}
@error object wc satisfies WithInvariant {}
@error object wch satisfies WithInvariant<Holder> {}
@error object gwc satisfies Generics.WithInvariant {}
@error object gwch satisfies Generics.WithInvariant<Holder> {}

object wco satisfies WithCovariant {}
@error object wcho satisfies WithCovariant<Holder> {}
object gwco satisfies Generics.WithCovariant {}
@error object gwcho satisfies Generics.WithCovariant<Holder> {}

object wci satisfies WithContravariant {}
@error object wchi satisfies WithContravariant<Holder> {}
object gwci satisfies Generics.WithContravariant {}
@error object gwchi satisfies Generics.WithContravariant<Holder> {}

@error method<Holder>();
@error this.method<Holder>();
Expand Down

0 comments on commit 3628de5

Please sign in to comment.