@@ -407,6 +407,87 @@ void TypeChecker::bindExtension(ExtensionDecl *ext) {
407407 ::bindExtensionDecl (ext, *this );
408408}
409409
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+
410491static void typeCheckFunctionsAndExternalDecls (TypeChecker &TC) {
411492 unsigned currentFunctionIdx = 0 ;
412493 unsigned currentExternalDef = TC.Context .LastCheckedExternalDefinition ;
@@ -462,50 +543,7 @@ static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) {
462543 if (nominal->isInvalid () || TC.Context .hadError ())
463544 continue ;
464545
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);
509547 }
510548
511549 // Complete any conformances that we used.
0 commit comments