8
8
* http://polymer.github.io/PATENTS.txt
9
9
*/
10
10
11
- import { BigCollectionType , CollectionType , EntityType , InterfaceType , ReferenceType , SlotType , Type , TypeVariable } from '../type.js' ;
11
+ import { BigCollectionType , CollectionType , EntityType , InterfaceType , ReferenceType , SlotType , Type , TypeVariable , TupleType } from '../type.js' ;
12
12
import { Direction } from '../manifest-ast-nodes.js' ;
13
13
14
14
export interface TypeListInfo {
@@ -24,7 +24,24 @@ export class TypeChecker {
24
24
25
25
// NOTE: you almost definitely don't want to call this function, if you think
26
26
// you do, talk to shans@.
27
- private static getResolution ( candidate : Type , options : TypeCheckOptions ) {
27
+ private static getResolution ( candidate : Type , options : TypeCheckOptions ) : Type | null {
28
+ if ( candidate . isCollectionType ( ) ) {
29
+ const resolution = TypeChecker . getResolution ( candidate . collectionType , options ) ;
30
+ return ( resolution !== null ) ? resolution . collectionOf ( ) : null ;
31
+ }
32
+ if ( candidate . isBigCollectionType ( ) ) {
33
+ const resolution = TypeChecker . getResolution ( candidate . bigCollectionType , options ) ;
34
+ return ( resolution !== null ) ? resolution . bigCollectionOf ( ) : null ;
35
+ }
36
+ if ( candidate . isReferenceType ( ) ) {
37
+ const resolution = TypeChecker . getResolution ( candidate . referredType , options ) ;
38
+ return ( resolution !== null ) ? resolution . referenceTo ( ) : null ;
39
+ }
40
+ if ( candidate . isTupleType ( ) ) {
41
+ const resolutions = candidate . innerTypes . map ( t => TypeChecker . getResolution ( t , options ) ) ;
42
+ return resolutions . every ( r => r !== null ) ? new TupleType ( resolutions ) : null ;
43
+ }
44
+
28
45
if ( ! ( candidate instanceof TypeVariable ) ) {
29
46
return candidate ;
30
47
}
@@ -95,18 +112,7 @@ export class TypeChecker {
95
112
}
96
113
}
97
114
98
- const candidate = baseType . resolvedType ( ) ;
99
-
100
- if ( candidate . isCollectionType ( ) ) {
101
- const resolution = TypeChecker . getResolution ( candidate . collectionType , options ) ;
102
- return ( resolution !== null ) ? resolution . collectionOf ( ) : null ;
103
- }
104
- if ( candidate . isBigCollectionType ( ) ) {
105
- const resolution = TypeChecker . getResolution ( candidate . bigCollectionType , options ) ;
106
- return ( resolution !== null ) ? resolution . bigCollectionOf ( ) : null ;
107
- }
108
-
109
- return TypeChecker . getResolution ( candidate , options ) ;
115
+ return TypeChecker . getResolution ( baseType . resolvedType ( ) , options ) ;
110
116
}
111
117
112
118
static _tryMergeTypeVariable ( base : Type , onto : Type , options : { typeErrors ?: string [ ] } = { } ) : Type {
@@ -150,9 +156,23 @@ export class TypeChecker {
150
156
}
151
157
152
158
static _tryMergeConstraints ( handleType : Type , { type, relaxed, direction} : TypeListInfo , options : { typeErrors ?: string [ ] } = { } ) : boolean {
153
- let [ primitiveHandleType , primitiveConnectionType ] = Type . unwrapPair ( handleType . resolvedType ( ) , type . resolvedType ( ) ) ;
159
+ const [ handleInnerTypes , connectionInnerTypes ] = Type . tryUnwrapMulti ( handleType . resolvedType ( ) , type . resolvedType ( ) ) ;
160
+ // If both handle and connection are matching type containers with multiple arguments,
161
+ // merge constraints pairwaise for all inner types.
162
+ if ( handleInnerTypes != null ) {
163
+ if ( handleInnerTypes . length !== connectionInnerTypes . length ) return false ;
164
+ for ( let i = 0 ; i < handleInnerTypes . length ; i ++ ) {
165
+ if ( ! this . _tryMergeConstraints ( handleInnerTypes [ i ] , { type : connectionInnerTypes [ i ] , relaxed, direction} , options ) ) {
166
+ return false ;
167
+ }
168
+ }
169
+ return true ;
170
+ }
171
+
172
+ const [ primitiveHandleType , primitiveConnectionType ] = Type . unwrapPair ( handleType . resolvedType ( ) , type . resolvedType ( ) ) ;
173
+
154
174
if ( primitiveHandleType instanceof TypeVariable ) {
155
- while ( primitiveConnectionType . isTypeContainer ( ) ) {
175
+ if ( primitiveConnectionType . isTypeContainer ( ) ) {
156
176
if ( primitiveHandleType . variable . resolution != null
157
177
|| primitiveHandleType . variable . canReadSubset != null
158
178
|| primitiveHandleType . variable . canWriteSuperset != null ) {
@@ -162,21 +182,21 @@ export class TypeChecker {
162
182
// If this is an undifferentiated variable then we need to create structure to match against. That's
163
183
// allowed because this variable could represent anything, and it needs to represent this structure
164
184
// in order for type resolution to succeed.
165
- const newVar = TypeVariable . make ( 'a' ) ;
166
185
if ( primitiveConnectionType instanceof CollectionType ) {
167
- primitiveHandleType . variable . resolution = new CollectionType ( newVar ) ;
186
+ primitiveHandleType . variable . resolution = new CollectionType ( TypeVariable . make ( 'a' ) ) ;
168
187
} else if ( primitiveConnectionType instanceof BigCollectionType ) {
169
- primitiveHandleType . variable . resolution = new BigCollectionType ( newVar ) ;
188
+ primitiveHandleType . variable . resolution = new BigCollectionType ( TypeVariable . make ( 'a' ) ) ;
189
+ } else if ( primitiveConnectionType instanceof ReferenceType ) {
190
+ primitiveHandleType . variable . resolution = new ReferenceType ( TypeVariable . make ( 'a' ) ) ;
191
+ } else if ( primitiveConnectionType instanceof TupleType ) {
192
+ primitiveHandleType . variable . resolution = new TupleType (
193
+ primitiveConnectionType . innerTypes . map ( ( _ , idx ) => TypeVariable . make ( `a${ idx } ` ) ) ) ;
170
194
} else {
171
- primitiveHandleType . variable . resolution = new ReferenceType ( newVar ) ;
195
+ throw new TypeError ( `Unrecognized type container: ${ primitiveConnectionType . tag } ` ) ;
172
196
}
173
197
174
- const unwrap = Type . unwrapPair ( primitiveHandleType . resolvedType ( ) , primitiveConnectionType ) ;
175
- [ primitiveHandleType , primitiveConnectionType ] = unwrap ;
176
- if ( ! ( primitiveHandleType instanceof TypeVariable ) ) {
177
- // This should never happen, and the guard above is just here so we type-check.
178
- throw new TypeError ( 'unwrapping a wrapped TypeVariable somehow didn\'t become a TypeVariable' ) ;
179
- }
198
+ // Call recursively to unwrap and merge constraints of potentially multiple type variables (e.g. for tuples).
199
+ return this . _tryMergeConstraints ( primitiveHandleType . resolvedType ( ) , { type : primitiveConnectionType , relaxed, direction} , options ) ;
180
200
}
181
201
182
202
if ( direction === 'writes' || direction === 'reads writes' || direction === '`provides' ) {
0 commit comments