OLD | NEW |
| (Empty) |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 library kernel.type_substitute_bounds_test; | |
5 | |
6 import 'package:kernel/kernel.dart'; | |
7 import 'package:kernel/type_algebra.dart'; | |
8 import 'package:test/test.dart'; | |
9 import 'type_parser.dart'; | |
10 | |
11 final List<TestCase> testCases = <TestCase>[ | |
12 testCase('T', {'T': bound('_', 'String')}, 'String'), | |
13 testCase('List<T>', {'T': bound('_', 'String')}, 'List<String>'), | |
14 testCase('List<List<T>>', {'T': bound('_', 'String')}, 'List<List<String>>'), | |
15 testCase('(T) => T', {'T': bound('_', 'String')}, '(_) => String'), | |
16 testCase('<G>(G,T) => T', {'T': bound('_', 'String')}, '<G>(G,_) => String'), | |
17 testCase( | |
18 '<G>(G,x:T) => T', {'T': bound('_', 'String')}, '<G>(G,x:_) => String'), | |
19 testCase('<G:T>(G) => G', {'T': bound('_', 'String')}, '<G:_>(G) => G'), | |
20 testCase('<G:T>(G) => G', {'T': bound('int', 'num')}, '<G:int>(G) => G'), | |
21 testCase('<G>(T,G) => void', {'T': bound('_', 'String')}, '<G>(_,G) => void'), | |
22 testCase('(T) => void', {'T': bound('_', 'String')}, '(_) => void'), | |
23 testCase('(int) => T', {'T': bound('_', 'String')}, '(int) => String'), | |
24 testCase('(int) => int', {'T': bound('_', 'String')}, '(int) => int'), | |
25 testCase('((T) => int) => int', {'T': bound('_', 'String')}, | |
26 '((String) => int) => int'), | |
27 testCase('<E>(<F>(T) => int) => int', {'T': bound('_', 'String')}, | |
28 '<E>(<F>(String) => int) => int'), | |
29 testCase('(<F>(T) => int) => int', {'T': bound('_', 'String')}, | |
30 '(<F>(String) => int) => int'), | |
31 testCase('<E>((T) => int) => int', {'T': bound('_', 'String')}, | |
32 '<E>((String) => int) => int'), | |
33 ]; | |
34 | |
35 class TestCase { | |
36 final String type; | |
37 final Map<String, TypeBound> bounds; | |
38 final String expected; | |
39 | |
40 TestCase(this.type, this.bounds, this.expected); | |
41 | |
42 String toString() { | |
43 var substitution = bounds.keys.map((key) { | |
44 var bound = bounds[key]; | |
45 return '${bound.lower} <: $key <: ${bound.upper}'; | |
46 }).join(','); | |
47 return '$type [$substitution] <: $expected'; | |
48 } | |
49 } | |
50 | |
51 class TypeBound { | |
52 final String lower, upper; | |
53 | |
54 TypeBound(this.lower, this.upper); | |
55 } | |
56 | |
57 TypeBound bound(String lower, String upper) => new TypeBound(lower, upper); | |
58 | |
59 TestCase testCase(String type, Map<String, TypeBound> bounds, String expected) { | |
60 return new TestCase(type, bounds, expected); | |
61 } | |
62 | |
63 main() { | |
64 for (var testCase in testCases) { | |
65 test('$testCase', () { | |
66 var environment = new LazyTypeEnvironment(); | |
67 var type = environment.parse(testCase.type); | |
68 var upperBounds = <TypeParameter, DartType>{}; | |
69 var lowerBounds = <TypeParameter, DartType>{}; | |
70 testCase.bounds.forEach((String name, TypeBound bounds) { | |
71 var parameter = environment.getTypeParameter(name); | |
72 upperBounds[parameter] = environment.parse(bounds.upper); | |
73 lowerBounds[parameter] = environment.parse(bounds.lower); | |
74 }); | |
75 var substituted = Substitution | |
76 .fromUpperAndLowerBounds(upperBounds, lowerBounds) | |
77 .substituteType(type); | |
78 var expected = environment.parse(testCase.expected); | |
79 if (substituted != expected) { | |
80 fail('Expected `$expected` but got `$substituted`'); | |
81 } | |
82 }); | |
83 } | |
84 } | |
OLD | NEW |