OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library fasta.kernel_library_builder; | 5 library fasta.kernel_library_builder; |
6 | 6 |
7 import 'package:front_end/src/fasta/scanner/token.dart' show Token; | 7 import 'package:front_end/src/fasta/scanner/token.dart' show Token; |
8 | 8 |
9 import 'package:kernel/ast.dart'; | 9 import 'package:kernel/ast.dart'; |
10 | 10 |
11 import 'package:kernel/clone.dart' show CloneVisitor; | 11 import 'package:kernel/clone.dart' show CloneVisitor; |
12 | 12 |
13 import '../errors.dart' show internalError; | 13 import '../errors.dart' show internalError; |
14 | 14 |
15 import '../loader.dart' show Loader; | 15 import '../loader.dart' show Loader; |
16 | 16 |
17 import '../modifier.dart' show abstractMask, staticMask; | 17 import '../modifier.dart' |
| 18 show abstractMask, namedMixinApplicationMask, staticMask; |
18 | 19 |
19 import '../source/source_library_builder.dart' | 20 import '../source/source_library_builder.dart' |
20 show DeclarationBuilder, SourceLibraryBuilder; | 21 show DeclarationBuilder, SourceLibraryBuilder; |
21 | 22 |
22 import '../source/source_class_builder.dart' show SourceClassBuilder; | 23 import '../source/source_class_builder.dart' show SourceClassBuilder; |
23 | 24 |
24 import '../util/relativize.dart' show relativizeUri; | 25 import '../util/relativize.dart' show relativizeUri; |
25 | 26 |
26 import 'kernel_builder.dart' | 27 import 'kernel_builder.dart' |
27 show | 28 show |
28 AccessErrorBuilder, | 29 AccessErrorBuilder, |
29 Builder, | 30 Builder, |
30 BuiltinTypeBuilder, | 31 BuiltinTypeBuilder, |
31 ClassBuilder, | 32 ClassBuilder, |
32 ConstructorReferenceBuilder, | 33 ConstructorReferenceBuilder, |
33 FormalParameterBuilder, | 34 FormalParameterBuilder, |
34 FunctionTypeAliasBuilder, | 35 FunctionTypeAliasBuilder, |
35 InvalidTypeBuilder, | 36 InvalidTypeBuilder, |
36 KernelConstructorBuilder, | 37 KernelConstructorBuilder, |
37 KernelEnumBuilder, | 38 KernelEnumBuilder, |
38 KernelFieldBuilder, | 39 KernelFieldBuilder, |
39 KernelFormalParameterBuilder, | 40 KernelFormalParameterBuilder, |
40 KernelFunctionTypeAliasBuilder, | 41 KernelFunctionTypeAliasBuilder, |
41 KernelFunctionTypeBuilder, | 42 KernelFunctionTypeBuilder, |
42 KernelInvalidTypeBuilder, | 43 KernelInvalidTypeBuilder, |
43 KernelMixinApplicationBuilder, | 44 KernelMixinApplicationBuilder, |
44 KernelNamedMixinApplicationBuilder, | |
45 KernelNamedTypeBuilder, | 45 KernelNamedTypeBuilder, |
46 KernelProcedureBuilder, | 46 KernelProcedureBuilder, |
47 KernelTypeBuilder, | 47 KernelTypeBuilder, |
48 KernelTypeVariableBuilder, | 48 KernelTypeVariableBuilder, |
49 LibraryBuilder, | 49 LibraryBuilder, |
50 MemberBuilder, | 50 MemberBuilder, |
51 MetadataBuilder, | 51 MetadataBuilder, |
52 NamedMixinApplicationBuilder, | 52 NamedTypeBuilder, |
53 PrefixBuilder, | 53 PrefixBuilder, |
54 ProcedureBuilder, | 54 ProcedureBuilder, |
55 Scope, | 55 Scope, |
56 TypeBuilder, | 56 TypeBuilder, |
57 TypeVariableBuilder, | 57 TypeVariableBuilder, |
58 compareProcedures; | 58 compareProcedures; |
59 | 59 |
60 class KernelLibraryBuilder | 60 class KernelLibraryBuilder |
61 extends SourceLibraryBuilder<KernelTypeBuilder, Library> { | 61 extends SourceLibraryBuilder<KernelTypeBuilder, Library> { |
62 final Library library; | 62 final Library library; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 } | 97 } |
98 | 98 |
99 void addClass( | 99 void addClass( |
100 List<MetadataBuilder> metadata, | 100 List<MetadataBuilder> metadata, |
101 int modifiers, | 101 int modifiers, |
102 String className, | 102 String className, |
103 List<TypeVariableBuilder> typeVariables, | 103 List<TypeVariableBuilder> typeVariables, |
104 KernelTypeBuilder supertype, | 104 KernelTypeBuilder supertype, |
105 List<KernelTypeBuilder> interfaces, | 105 List<KernelTypeBuilder> interfaces, |
106 int charOffset) { | 106 int charOffset) { |
107 assert(currentDeclaration.parent == libraryDeclaration); | 107 // Nested declaration began in `OutlineBuilder.beginClassDeclaration`. |
108 Map<String, MemberBuilder> members = currentDeclaration.members; | 108 var declaration = endNestedDeclaration()..resolveTypes(typeVariables, this); |
109 Map<String, MemberBuilder> constructors = currentDeclaration.constructors; | 109 assert(declaration.parent == libraryDeclaration); |
110 Map<String, MemberBuilder> setters = currentDeclaration.setters; | 110 Map<String, MemberBuilder> members = declaration.members; |
| 111 Map<String, MemberBuilder> constructors = declaration.constructors; |
| 112 Map<String, MemberBuilder> setters = declaration.setters; |
111 | 113 |
112 Scope classScope = new Scope( | 114 Scope classScope = new Scope( |
113 members, setters, scope.withTypeVariables(typeVariables), | 115 members, setters, scope.withTypeVariables(typeVariables), |
114 isModifiable: false); | 116 isModifiable: false); |
115 | 117 |
116 // When looking up a constructor, we don't consider type variables or the | 118 // When looking up a constructor, we don't consider type variables or the |
117 // library scope. | 119 // library scope. |
118 Scope constructorScope = | 120 Scope constructorScope = |
119 new Scope(constructors, null, null, isModifiable: false); | 121 new Scope(constructors, null, null, isModifiable: false); |
120 ClassBuilder cls = new SourceClassBuilder( | 122 ClassBuilder cls = new SourceClassBuilder( |
121 metadata, | 123 metadata, |
122 modifiers, | 124 modifiers, |
123 className, | 125 className, |
124 typeVariables, | 126 typeVariables, |
125 supertype, | 127 applyMixins(supertype, |
| 128 subclassName: className, typeVariables: typeVariables), |
126 interfaces, | 129 interfaces, |
127 classScope, | 130 classScope, |
128 constructorScope, | 131 constructorScope, |
129 this, | 132 this, |
130 new List<ConstructorReferenceBuilder>.from(constructorReferences), | 133 new List<ConstructorReferenceBuilder>.from(constructorReferences), |
131 charOffset); | 134 charOffset); |
132 constructorReferences.clear(); | 135 constructorReferences.clear(); |
| 136 Map<String, TypeVariableBuilder> typeVariablesByName = |
| 137 checkTypeVariables(typeVariables, cls); |
133 void setParent(String name, MemberBuilder member) { | 138 void setParent(String name, MemberBuilder member) { |
134 while (member != null) { | 139 while (member != null) { |
135 member.parent = cls; | 140 member.parent = cls; |
136 member = member.next; | 141 member = member.next; |
137 } | 142 } |
138 } | 143 } |
139 | 144 |
140 members.forEach(setParent); | 145 void setParentAndCheckConflicts(String name, MemberBuilder member) { |
141 constructors.forEach(setParent); | 146 if (typeVariablesByName != null) { |
| 147 TypeVariableBuilder tv = typeVariablesByName[name]; |
| 148 if (tv != null) { |
| 149 cls.addCompileTimeError( |
| 150 member.charOffset, "Conflict with type variable '$name'."); |
| 151 cls.addCompileTimeError(tv.charOffset, "This is the type variable."); |
| 152 } |
| 153 } |
| 154 setParent(name, member); |
| 155 } |
| 156 |
| 157 members.forEach(setParentAndCheckConflicts); |
| 158 constructors.forEach(setParentAndCheckConflicts); |
| 159 // Formally, a setter has the name `id=`, so it can never conflict with a |
| 160 // type variable. |
142 setters.forEach(setParent); | 161 setters.forEach(setParent); |
143 // Nested declaration began in `OutlineBuilder.beginClassDeclaration`. | |
144 endNestedDeclaration().resolveTypes(typeVariables, this); | |
145 addBuilder(className, cls, charOffset); | 162 addBuilder(className, cls, charOffset); |
146 } | 163 } |
147 | 164 |
| 165 Map<String, TypeVariableBuilder> checkTypeVariables( |
| 166 List<TypeVariableBuilder> typeVariables, Builder owner) { |
| 167 if (typeVariables?.isEmpty ?? true) return null; |
| 168 Map<String, TypeVariableBuilder> typeVariablesByName = |
| 169 <String, TypeVariableBuilder>{}; |
| 170 for (TypeVariableBuilder tv in typeVariables) { |
| 171 TypeVariableBuilder existing = typeVariablesByName[tv.name]; |
| 172 if (existing != null) { |
| 173 addCompileTimeError(tv.charOffset, |
| 174 "A type variable can't have the same name as another."); |
| 175 addCompileTimeError( |
| 176 existing.charOffset, "The other type variable named '${tv.name}'."); |
| 177 } else { |
| 178 typeVariablesByName[tv.name] = tv; |
| 179 if (owner is ClassBuilder) { |
| 180 // Only classes and type variables can't have the same name. See |
| 181 // [#29555](https://github.com/dart-lang/sdk/issues/29555). |
| 182 if (tv.name == owner.name) { |
| 183 addCompileTimeError( |
| 184 tv.charOffset, |
| 185 "A type variable can't have the same name as its enclosing " |
| 186 "declaration."); |
| 187 } |
| 188 } |
| 189 } |
| 190 } |
| 191 return typeVariablesByName; |
| 192 } |
| 193 |
| 194 KernelTypeBuilder applyMixin( |
| 195 KernelTypeBuilder supertype, KernelTypeBuilder mixin, String signature, |
| 196 {List<MetadataBuilder> metadata, |
| 197 String name, |
| 198 List<TypeVariableBuilder> typeVariables, |
| 199 int modifiers: abstractMask, |
| 200 List<KernelTypeBuilder> interfaces, |
| 201 int charOffset: -1}) { |
| 202 var constructors = <String, MemberBuilder>{}; |
| 203 bool isNamed = name != null; |
| 204 SourceClassBuilder builder; |
| 205 if (isNamed) { |
| 206 modifiers |= namedMixinApplicationMask; |
| 207 } else { |
| 208 name = supertype.name; |
| 209 int index = name.indexOf("^"); |
| 210 if (index != -1) { |
| 211 name = name.substring(0, index); |
| 212 } |
| 213 name = "$name&${mixin.name}$signature"; |
| 214 builder = mixinApplicationClasses[name]; |
| 215 } |
| 216 if (builder == null) { |
| 217 builder = new SourceClassBuilder( |
| 218 metadata, |
| 219 modifiers, |
| 220 name, |
| 221 typeVariables, |
| 222 supertype, |
| 223 interfaces, |
| 224 new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{}, |
| 225 scope.withTypeVariables(typeVariables), |
| 226 isModifiable: false), |
| 227 new Scope(constructors, null, null, isModifiable: false), |
| 228 this, |
| 229 <ConstructorReferenceBuilder>[], |
| 230 charOffset, |
| 231 null, |
| 232 mixin); |
| 233 addBuilder(name, builder, charOffset); |
| 234 if (!isNamed) { |
| 235 mixinApplicationClasses[name] = builder; |
| 236 } |
| 237 } |
| 238 return addNamedType(name, <KernelTypeBuilder>[], charOffset) |
| 239 ..bind(isNamed ? builder : null); |
| 240 } |
| 241 |
| 242 KernelTypeBuilder applyMixins(KernelTypeBuilder type, |
| 243 {List<MetadataBuilder> metadata, |
| 244 String name, |
| 245 String subclassName, |
| 246 List<TypeVariableBuilder> typeVariables, |
| 247 int modifiers: abstractMask, |
| 248 List<KernelTypeBuilder> interfaces, |
| 249 int charOffset: -1}) { |
| 250 if (type is KernelMixinApplicationBuilder) { |
| 251 subclassName ??= name; |
| 252 List<List<String>> signatureParts = <List<String>>[]; |
| 253 Map<String, String> unresolved = <String, String>{}; |
| 254 Map<String, String> unresolvedReversed = <String, String>{}; |
| 255 int unresolvedCount = 0; |
| 256 Map<String, TypeBuilder> freeTypes = <String, TypeBuilder>{}; |
| 257 |
| 258 if (name == null || type.mixins.length != 1) { |
| 259 TypeBuilder last = type.mixins.last; |
| 260 |
| 261 /// Compute a signature of the type arguments used by the supertype and |
| 262 /// mixins. These types are free variables. At this point we can't |
| 263 /// trust that the number of type arguments match the type parameters, |
| 264 /// so we also need to be able to detect missing type arguments. To do |
| 265 /// so, we separate each list of type arguments by `^` and type |
| 266 /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would |
| 267 /// look like this: |
| 268 /// |
| 269 /// ^#U0^#U1&#U2 |
| 270 /// |
| 271 /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from |
| 272 /// `S`, `T`, and `U` respectively. |
| 273 /// |
| 274 /// As we can resolve any type parameters used at this point, those are |
| 275 /// named `#T0` and so forth. This reduces the number of free variables |
| 276 /// which is crucial for memory usage and the Dart VM's bootstrap |
| 277 /// sequence. |
| 278 /// |
| 279 /// For example, consider this use of mixin applications: |
| 280 /// |
| 281 /// class _InternalLinkedHashMap<K, V> extends _HashVMBase |
| 282 /// with |
| 283 /// MapMixin<K, V>, |
| 284 /// _LinkedHashMapMixin<K, V>, |
| 285 /// _HashBase, |
| 286 /// _OperatorEqualsAndHashCode {} |
| 287 /// |
| 288 /// In this case, only two variables are free, and we produce this |
| 289 /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the |
| 290 /// sames mixins but with missing type arguments for `MapMixin`, its |
| 291 /// signature would be: `^^^#T0&#T1^^`. |
| 292 /// |
| 293 /// Note that we do not need to compute a signature for a named mixin |
| 294 /// application with only one mixin as we don't have to invent a name |
| 295 /// for any classes in this situation. |
| 296 void analyzeArguments(TypeBuilder type) { |
| 297 if (name != null && type == last) { |
| 298 // The last mixin of a named mixin application doesn't contribute |
| 299 // to free variables. |
| 300 return; |
| 301 } |
| 302 if (type is NamedTypeBuilder) { |
| 303 List<String> part = <String>[]; |
| 304 for (int i = 0; i < (type.arguments?.length ?? 0); i++) { |
| 305 var argument = type.arguments[i]; |
| 306 String name; |
| 307 if (argument is NamedTypeBuilder) { |
| 308 if (argument.builder != null) { |
| 309 int index = typeVariables?.indexOf(argument.builder) ?? -1; |
| 310 if (index != -1) { |
| 311 name = "#T${index}"; |
| 312 } |
| 313 } else if (argument.arguments == null) { |
| 314 name = unresolved[argument.name] ??= "#U${unresolvedCount++}"; |
| 315 } |
| 316 } |
| 317 name ??= "#U${unresolvedCount++}"; |
| 318 unresolvedReversed[name] = argument.name; |
| 319 freeTypes[name] = argument; |
| 320 part.add(name); |
| 321 type.arguments[i] = |
| 322 new KernelNamedTypeBuilder(name, null, -1, fileUri); |
| 323 } |
| 324 signatureParts.add(part); |
| 325 } |
| 326 } |
| 327 |
| 328 analyzeArguments(type.supertype); |
| 329 type.mixins.forEach(analyzeArguments); |
| 330 } |
| 331 KernelTypeBuilder supertype = type.supertype; |
| 332 List<List<String>> currentSignatureParts = <List<String>>[]; |
| 333 int currentSignatureCount = 0; |
| 334 String computeSignature() { |
| 335 if (freeTypes.isEmpty) return ""; |
| 336 currentSignatureParts.add(signatureParts[currentSignatureCount++]); |
| 337 if (currentSignatureParts.any((l) => l.isNotEmpty)) { |
| 338 return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}"; |
| 339 } else { |
| 340 return ""; |
| 341 } |
| 342 } |
| 343 |
| 344 Map<String, TypeVariableBuilder> computeTypeVariables() { |
| 345 Map<String, TypeVariableBuilder> variables = |
| 346 <String, TypeVariableBuilder>{}; |
| 347 for (List<String> strings in currentSignatureParts) { |
| 348 for (String name in strings) { |
| 349 variables[name] ??= addTypeVariable(name, null, -1); |
| 350 } |
| 351 } |
| 352 return variables; |
| 353 } |
| 354 |
| 355 checkArguments(t) { |
| 356 for (var argument in t.arguments ?? const []) { |
| 357 if (argument.builder == null && argument.name.startsWith("#")) { |
| 358 throw "No builder on ${argument.name}"; |
| 359 } |
| 360 } |
| 361 } |
| 362 |
| 363 computeSignature(); // This combines the supertype with the first mixin. |
| 364 for (int i = 0; i < type.mixins.length - 1; i++) { |
| 365 Set<String> supertypeArguments = new Set<String>(); |
| 366 for (var part in currentSignatureParts) { |
| 367 supertypeArguments.addAll(part); |
| 368 } |
| 369 String signature = computeSignature(); |
| 370 var variables = computeTypeVariables(); |
| 371 if (supertypeArguments.isNotEmpty) { |
| 372 supertype = addNamedType( |
| 373 supertype.name, |
| 374 supertypeArguments |
| 375 .map((n) => addNamedType(n, null, -1)..bind(variables[n])) |
| 376 .toList(), |
| 377 -1); |
| 378 } |
| 379 KernelNamedTypeBuilder mixin = type.mixins[i]; |
| 380 for (var type in mixin.arguments ?? const []) { |
| 381 type.bind(variables[type.name]); |
| 382 } |
| 383 checkArguments(supertype); |
| 384 checkArguments(mixin); |
| 385 supertype = applyMixin(supertype, mixin, signature, |
| 386 typeVariables: |
| 387 new List<TypeVariableBuilder>.from(variables.values)); |
| 388 } |
| 389 KernelNamedTypeBuilder mixin = type.mixins.last; |
| 390 |
| 391 Set<String> supertypeArguments = new Set<String>(); |
| 392 for (var part in currentSignatureParts) { |
| 393 supertypeArguments.addAll(part); |
| 394 } |
| 395 String signature = name == null ? computeSignature() : ""; |
| 396 var variables; |
| 397 if (name == null) { |
| 398 variables = computeTypeVariables(); |
| 399 typeVariables = new List<TypeVariableBuilder>.from(variables.values); |
| 400 if (supertypeArguments.isNotEmpty) { |
| 401 supertype = addNamedType( |
| 402 supertype.name, |
| 403 supertypeArguments |
| 404 .map((n) => addNamedType(n, null, -1)..bind(variables[n])) |
| 405 .toList(), |
| 406 -1); |
| 407 } |
| 408 } else { |
| 409 if (supertypeArguments.isNotEmpty) { |
| 410 supertype = addNamedType(supertype.name, |
| 411 supertypeArguments.map((n) => freeTypes[n]).toList(), -1); |
| 412 } |
| 413 } |
| 414 |
| 415 if (name == null) { |
| 416 for (var type in mixin.arguments ?? const []) { |
| 417 type.bind(variables[type.name]); |
| 418 } |
| 419 } |
| 420 checkArguments(supertype); |
| 421 checkArguments(mixin); |
| 422 |
| 423 KernelNamedTypeBuilder t = applyMixin(supertype, mixin, signature, |
| 424 metadata: metadata, |
| 425 name: name, |
| 426 typeVariables: typeVariables, |
| 427 modifiers: modifiers, |
| 428 interfaces: interfaces, |
| 429 charOffset: charOffset); |
| 430 if (name == null) { |
| 431 var builder = t.builder; |
| 432 t = addNamedType( |
| 433 t.name, freeTypes.keys.map((k) => freeTypes[k]).toList(), -1); |
| 434 if (builder != null) { |
| 435 t.bind(builder); |
| 436 } |
| 437 } |
| 438 return t; |
| 439 } else { |
| 440 return type; |
| 441 } |
| 442 } |
| 443 |
148 void addNamedMixinApplication( | 444 void addNamedMixinApplication( |
149 List<MetadataBuilder> metadata, | 445 List<MetadataBuilder> metadata, |
150 String name, | 446 String name, |
151 List<TypeVariableBuilder> typeVariables, | 447 List<TypeVariableBuilder> typeVariables, |
152 int modifiers, | 448 int modifiers, |
153 KernelTypeBuilder mixinApplication, | 449 KernelTypeBuilder mixinApplication, |
154 List<KernelTypeBuilder> interfaces, | 450 List<KernelTypeBuilder> interfaces, |
155 int charOffset) { | 451 int charOffset) { |
156 NamedMixinApplicationBuilder builder = | |
157 new KernelNamedMixinApplicationBuilder(metadata, name, typeVariables, | |
158 modifiers, mixinApplication, interfaces, this, charOffset); | |
159 // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`. | 452 // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`. |
160 endNestedDeclaration().resolveTypes(typeVariables, this); | 453 endNestedDeclaration().resolveTypes(typeVariables, this); |
161 addBuilder(name, builder, charOffset); | 454 KernelNamedTypeBuilder supertype = applyMixins(mixinApplication, |
| 455 metadata: metadata, |
| 456 name: name, |
| 457 typeVariables: typeVariables, |
| 458 modifiers: modifiers, |
| 459 interfaces: interfaces, |
| 460 charOffset: charOffset); |
| 461 checkTypeVariables(typeVariables, supertype.builder); |
162 } | 462 } |
163 | 463 |
164 void addField(List<MetadataBuilder> metadata, int modifiers, | 464 void addField(List<MetadataBuilder> metadata, int modifiers, |
165 KernelTypeBuilder type, String name, int charOffset, Token initializer) { | 465 KernelTypeBuilder type, String name, int charOffset, Token initializer) { |
166 addBuilder( | 466 addBuilder( |
167 name, | 467 name, |
168 new KernelFieldBuilder( | 468 new KernelFieldBuilder( |
169 metadata, type, name, modifiers, this, charOffset, initializer), | 469 metadata, type, name, modifiers, this, charOffset, initializer), |
170 charOffset); | 470 charOffset); |
171 } | 471 } |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 int count = boundlessTypeVariables.length; | 835 int count = boundlessTypeVariables.length; |
536 for (KernelTypeVariableBuilder builder in boundlessTypeVariables) { | 836 for (KernelTypeVariableBuilder builder in boundlessTypeVariables) { |
537 builder.finish(this, object); | 837 builder.finish(this, object); |
538 } | 838 } |
539 boundlessTypeVariables.clear(); | 839 boundlessTypeVariables.clear(); |
540 return count; | 840 return count; |
541 } | 841 } |
542 | 842 |
543 @override | 843 @override |
544 void includePart(covariant KernelLibraryBuilder part) { | 844 void includePart(covariant KernelLibraryBuilder part) { |
| 845 part.mixinApplicationClasses |
| 846 .forEach((String name, SourceClassBuilder builder) { |
| 847 SourceClassBuilder existing = |
| 848 mixinApplicationClasses.putIfAbsent(name, () => builder); |
| 849 if (existing != builder) { |
| 850 part.scope.local.remove(name); |
| 851 } |
| 852 }); |
545 super.includePart(part); | 853 super.includePart(part); |
546 nativeMethods.addAll(part.nativeMethods); | 854 nativeMethods.addAll(part.nativeMethods); |
547 boundlessTypeVariables.addAll(part.boundlessTypeVariables); | 855 boundlessTypeVariables.addAll(part.boundlessTypeVariables); |
548 assert(mixinApplicationClasses.isEmpty); | |
549 } | 856 } |
550 } | 857 } |
OLD | NEW |