blob: d6482632c93d30e9c8b4bb72ea969c8c748cd6ec [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.7
library type_substitution_test;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common/elements.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/elements/types.dart';
import '../helpers/type_test_helper.dart';
DartType getType(ElementEnvironment elementEnvironment, String name) {
ClassEntity cls =
elementEnvironment.lookupClass(elementEnvironment.mainLibrary, 'Class');
FunctionEntity element = elementEnvironment.lookupClassMember(cls, name);
Expect.isNotNull(element);
FunctionType type = elementEnvironment.getFunctionType(element);
// Function signatures are used to be to provide void types (only occurring as
// as return types) and (inlined) function types (only occurring as method
// parameter types).
//
// Only a single type is used from each signature. That is, it is not the
// intention to check the whole signatures against eachother.
if (type.parameterTypes.isEmpty) {
// If parameters is empty, use return type.
return type.returnType;
} else {
// Otherwise use the first argument type.
return type.parameterTypes.first;
}
}
void main() {
asyncTest(() async {
await testAsInstanceOf();
await testTypeSubstitution();
});
}
testAsInstanceOf() async {
var env = await TypeEnvironment.create('''
class A<T> {}
class B<T> {}
class C<T> extends A<T> {}
class D<T> extends A<int> {}
class E<T> extends A<A<T>> {}
class F<T, U> extends B<F<T, String>> implements A<F<B<U>, int>> {}
main() {
new A();
new B();
new C();
new D();
new E();
new F();
}
''', options: [Flags.noSoundNullSafety]);
var types = env.types;
ClassEntity A = env.getElement("A");
ClassEntity B = env.getElement("B");
ClassEntity C = env.getElement("C");
ClassEntity D = env.getElement("D");
ClassEntity E = env.getElement("E");
ClassEntity F = env.getElement("F");
DartType intType = env['int'];
DartType stringType = env['String'];
InterfaceType C_int = env.instantiate(C, [intType]);
Expect.equals(env.instantiate(C, [intType]), C_int);
Expect.equals(env.instantiate(A, [intType]), types.asInstanceOf(C_int, A));
InterfaceType D_int = env.instantiate(D, [stringType]);
Expect.equals(env.instantiate(A, [intType]), types.asInstanceOf(D_int, A));
InterfaceType E_int = env.instantiate(E, [intType]);
Expect.equals(
env.instantiate(A, [
env.instantiate(A, [intType])
]),
types.asInstanceOf(E_int, A));
InterfaceType F_int_string = env.instantiate(F, [intType, stringType]);
Expect.equals(
env.instantiate(B, [
env.instantiate(F, [intType, stringType])
]),
types.asInstanceOf(F_int_string, B));
Expect.equals(
env.instantiate(A, [
env.instantiate(F, [
env.instantiate(B, [stringType]),
intType
])
]),
types.asInstanceOf(F_int_string, A));
}
/**
* Test that substitution of [parameters] by [arguments] in the type found
* through [name1] is the same as the type found through [name2].
*/
void testSubstitution(
DartTypes dartTypes,
ElementEnvironment elementEnvironment,
List<DartType> arguments,
List<DartType> parameters,
DartType type1,
DartType type2) {
DartType subst = dartTypes.subst(arguments, parameters, type1);
Expect.equals(
type2, subst, "$type1.subst($arguments,$parameters)=$subst != $type2");
}
testTypeSubstitution() async {
var env = await TypeEnvironment.create(r"""
class Class<T,S> {}
main() => new Class();
""", options: [Flags.noSoundNullSafety]);
var types = env.types;
InterfaceType Class_T_S = env["Class"];
Expect.isNotNull(Class_T_S);
Expect.isTrue(Class_T_S is InterfaceType);
Expect.equals(2, Class_T_S.typeArguments.length);
DartType T = Class_T_S.typeArguments[0];
Expect.isNotNull(T);
Expect.isTrue(T is TypeVariableType);
DartType S = Class_T_S.typeArguments[1];
Expect.isNotNull(S);
Expect.isTrue(S is TypeVariableType);
DartType intType = env['int'];
Expect.isNotNull(intType);
Expect.isTrue(intType is InterfaceType);
DartType StringType = env['String'];
Expect.isNotNull(StringType);
Expect.isTrue(StringType is InterfaceType);
ClassEntity ListClass = env.getElement('List');
ClassEntity MapClass = env.getElement('Map');
List<DartType> parameters = <DartType>[T, S];
List<DartType> arguments = <DartType>[intType, StringType];
testSubstitution(types, env.elementEnvironment, arguments, parameters,
types.voidType(), types.voidType());
testSubstitution(types, env.elementEnvironment, arguments, parameters,
types.dynamicType(), types.dynamicType());
testSubstitution(
types, env.elementEnvironment, arguments, parameters, intType, intType);
testSubstitution(types, env.elementEnvironment, arguments, parameters,
StringType, StringType);
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(ListClass, [intType]),
env.instantiate(ListClass, [intType]));
testSubstitution(types, env.elementEnvironment, arguments, parameters,
env.instantiate(ListClass, [T]), env.instantiate(ListClass, [intType]));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(ListClass, [S]),
env.instantiate(ListClass, [StringType]));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(ListClass, [
env.instantiate(ListClass, [T])
]),
env.instantiate(ListClass, [
env.instantiate(ListClass, [intType])
]));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(ListClass, [types.dynamicType()]),
env.instantiate(ListClass, [types.dynamicType()]));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(MapClass, [intType, StringType]),
env.instantiate(MapClass, [intType, StringType]));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(MapClass, [T, StringType]),
env.instantiate(MapClass, [intType, StringType]));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
env.instantiate(MapClass, [types.dynamicType(), StringType]),
env.instantiate(MapClass, [types.dynamicType(), StringType]));
testSubstitution(
types, env.elementEnvironment, arguments, parameters, T, intType);
testSubstitution(
types, env.elementEnvironment, arguments, parameters, S, StringType);
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
types.functionType(intType, [StringType], [], [], {}, [], []),
types.functionType(intType, [StringType], [], [], {}, [], []));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
types.functionType(types.voidType(), [T, S], [], [], {}, [], []),
types.functionType(
types.voidType(), [intType, StringType], [], [], {}, [], []));
testSubstitution(
types,
env.elementEnvironment,
arguments,
parameters,
types.functionType(
types.voidType(), [types.dynamicType()], [], [], {}, [], []),
types.functionType(
types.voidType(), [types.dynamicType()], [], [], {}, [], []));
}