@@ -407,6 +407,87 @@ void TypeChecker::bindExtension(ExtensionDecl *ext) {
407
407
::bindExtensionDecl (ext, *this );
408
408
}
409
409
410
+ static bool shouldValidateDeclForLayout (NominalTypeDecl *nominal, ValueDecl *VD) {
411
+ // For enums, we only need to validate enum elements to know
412
+ // the layout.
413
+ if (isa<EnumDecl>(nominal) &&
414
+ isa<EnumElementDecl>(VD))
415
+ return true ;
416
+
417
+ // For structs, we only need to validate stored properties to
418
+ // know the layout.
419
+ if (isa<StructDecl>(nominal) &&
420
+ (isa<VarDecl>(VD) &&
421
+ !cast<VarDecl>(VD)->isStatic () &&
422
+ (cast<VarDecl>(VD)->hasStorage () ||
423
+ VD->getAttrs ().hasAttribute <LazyAttr>())))
424
+ return true ;
425
+
426
+ // For classes, we need to validate properties and functions,
427
+ // but skipping nested types is OK.
428
+ if (isa<ClassDecl>(nominal) &&
429
+ !isa<TypeDecl>(VD))
430
+ return true ;
431
+
432
+ // For protocols, skip nested typealiases and nominal types.
433
+ if (isa<ProtocolDecl>(nominal) &&
434
+ !isa<GenericTypeDecl>(VD))
435
+ return true ;
436
+
437
+ return false ;
438
+ }
439
+
440
+ static void validateDeclForLayout (TypeChecker &TC, NominalTypeDecl *nominal) {
441
+ Optional<bool > lazyVarsAlreadyHaveImplementation;
442
+
443
+ for (auto *D : nominal->getMembers ()) {
444
+ auto VD = dyn_cast<ValueDecl>(D);
445
+ if (!VD)
446
+ continue ;
447
+
448
+ if (!shouldValidateDeclForLayout (nominal, VD))
449
+ continue ;
450
+
451
+ TC.validateDecl (VD);
452
+
453
+ // The only thing left to do is synthesize storage for lazy variables.
454
+ // We only have to do that if it's a type from another file, though.
455
+ // In NDEBUG builds, bail out as soon as we can.
456
+ #ifdef NDEBUG
457
+ if (lazyVarsAlreadyHaveImplementation.hasValue () &&
458
+ lazyVarsAlreadyHaveImplementation.getValue ())
459
+ continue ;
460
+ #endif
461
+ auto *prop = dyn_cast<VarDecl>(D);
462
+ if (!prop)
463
+ continue ;
464
+
465
+ if (prop->getAttrs ().hasAttribute <LazyAttr>() && !prop->isStatic ()
466
+ && prop->getGetter ()) {
467
+ bool hasImplementation = prop->getGetter ()->hasBody ();
468
+
469
+ if (lazyVarsAlreadyHaveImplementation.hasValue ()) {
470
+ assert (lazyVarsAlreadyHaveImplementation.getValue () ==
471
+ hasImplementation &&
472
+ " only some lazy vars already have implementations" );
473
+ } else {
474
+ lazyVarsAlreadyHaveImplementation = hasImplementation;
475
+ }
476
+
477
+ if (!hasImplementation)
478
+ TC.completeLazyVarImplementation (prop);
479
+ }
480
+ }
481
+
482
+ // FIXME: We need to add implicit initializers and dtors when a decl is
483
+ // touched, because it affects vtable layout. If you're not defining the
484
+ // class, you shouldn't have to know what the vtable layout is.
485
+ if (auto *CD = dyn_cast<ClassDecl>(nominal)) {
486
+ TC.addImplicitConstructors (CD);
487
+ TC.addImplicitDestructor (CD);
488
+ }
489
+ }
490
+
410
491
static void typeCheckFunctionsAndExternalDecls (TypeChecker &TC) {
411
492
unsigned currentFunctionIdx = 0 ;
412
493
unsigned currentExternalDef = TC.Context .LastCheckedExternalDefinition ;
@@ -462,50 +543,7 @@ static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) {
462
543
if (nominal->isInvalid () || TC.Context .hadError ())
463
544
continue ;
464
545
465
- Optional<bool > lazyVarsAlreadyHaveImplementation;
466
-
467
- for (auto *D : nominal->getMembers ()) {
468
- auto VD = dyn_cast<ValueDecl>(D);
469
- if (!VD)
470
- continue ;
471
- TC.validateDecl (VD);
472
-
473
- // The only thing left to do is synthesize storage for lazy variables.
474
- // We only have to do that if it's a type from another file, though.
475
- // In NDEBUG builds, bail out as soon as we can.
476
- #ifdef NDEBUG
477
- if (lazyVarsAlreadyHaveImplementation.hasValue () &&
478
- lazyVarsAlreadyHaveImplementation.getValue ())
479
- continue ;
480
- #endif
481
- auto *prop = dyn_cast<VarDecl>(D);
482
- if (!prop)
483
- continue ;
484
-
485
- if (prop->getAttrs ().hasAttribute <LazyAttr>() && !prop->isStatic ()
486
- && prop->getGetter ()) {
487
- bool hasImplementation = prop->getGetter ()->hasBody ();
488
-
489
- if (lazyVarsAlreadyHaveImplementation.hasValue ()) {
490
- assert (lazyVarsAlreadyHaveImplementation.getValue () ==
491
- hasImplementation &&
492
- " only some lazy vars already have implementations" );
493
- } else {
494
- lazyVarsAlreadyHaveImplementation = hasImplementation;
495
- }
496
-
497
- if (!hasImplementation)
498
- TC.completeLazyVarImplementation (prop);
499
- }
500
- }
501
-
502
- // FIXME: We need to add implicit initializers and dtors when a decl is
503
- // touched, because it affects vtable layout. If you're not defining the
504
- // class, you shouldn't have to know what the vtable layout is.
505
- if (auto *CD = dyn_cast<ClassDecl>(nominal)) {
506
- TC.addImplicitConstructors (CD);
507
- TC.addImplicitDestructor (CD);
508
- }
546
+ validateDeclForLayout (TC, nominal);
509
547
}
510
548
511
549
// Complete any conformances that we used.
0 commit comments