@@ -944,8 +944,9 @@ static void inferProtocolMemberAvailability(ClangImporter::Implementation &impl,
944
944
applyAvailableAttribute (valueDecl, requiredRange, C);
945
945
}
946
946
947
- // / Add a domain error member, as required by conformance to _BridgedNSError
948
- // / Returns true on success, false on failure
947
+ // / Add a domain error member, as required by conformance to
948
+ // / _BridgedStoredNSError.
949
+ // / \returns true on success, false on failure
949
950
static bool addErrorDomain (NominalTypeDecl *swiftDecl,
950
951
clang::NamedDecl *errorDomainDecl,
951
952
ClangImporter::Implementation &importer) {
@@ -2151,12 +2152,17 @@ namespace {
2151
2152
// / TypeCheckPattern.cpp as well.
2152
2153
Decl *importEnumCaseAlias (Identifier name,
2153
2154
const clang::EnumConstantDecl *alias,
2154
- EnumElementDecl *original,
2155
+ ValueDecl *original,
2155
2156
const clang::EnumDecl *clangEnum,
2156
- NominalTypeDecl *importedEnum) {
2157
+ NominalTypeDecl *importedEnum,
2158
+ DeclContext *importIntoDC = nullptr ) {
2157
2159
if (name.empty ())
2158
2160
return nullptr ;
2159
-
2161
+
2162
+ // Default the DeclContext to the enum type.
2163
+ if (!importIntoDC)
2164
+ importIntoDC = importedEnum;
2165
+
2160
2166
// Construct the original constant. Enum constants without payloads look
2161
2167
// like simple values, but actually have type 'MyEnum.Type -> MyEnum'.
2162
2168
auto constantRef = new (Impl.SwiftContext ) DeclRefExpr (original,
@@ -2170,7 +2176,7 @@ namespace {
2170
2176
typeRef);
2171
2177
instantiate->setType (importedEnumTy);
2172
2178
2173
- Decl *CD = Impl.createConstant (name, importedEnum , importedEnumTy,
2179
+ Decl *CD = Impl.createConstant (name, importIntoDC , importedEnumTy,
2174
2180
instantiate, ConstantConvertKind::None,
2175
2181
/* isStatic*/ true , alias);
2176
2182
Impl.importAttributes (alias, CD);
@@ -2256,7 +2262,9 @@ namespace {
2256
2262
auto name = importedName.Imported .getBaseName ();
2257
2263
2258
2264
// Create the enum declaration and record it.
2265
+ StructDecl *errorWrapper = nullptr ;
2259
2266
NominalTypeDecl *result;
2267
+ NominalTypeDecl *enumeratorContext;
2260
2268
auto enumInfo = Impl.getEnumInfo (decl);
2261
2269
auto enumKind = enumInfo.getKind ();
2262
2270
switch (enumKind) {
@@ -2295,6 +2303,7 @@ namespace {
2295
2303
/* setterAccessibility=*/ Accessibility::Public);
2296
2304
2297
2305
result = structDecl;
2306
+ enumeratorContext = structDecl;
2298
2307
break ;
2299
2308
}
2300
2309
@@ -2312,9 +2321,80 @@ namespace {
2312
2321
if (!underlyingType)
2313
2322
return nullptr ;
2314
2323
2324
+ // / Basic information about the enum type we're building.
2325
+ Identifier enumName = name;
2326
+ DeclContext *enumDC = dc;
2327
+ SourceLoc loc = Impl.importSourceLoc (decl->getLocStart ());
2328
+
2329
+ // If this is an error enum, form the error wrapper type,
2330
+ // which is a struct containing an NSError instance.
2331
+ ProtocolDecl *bridgedNSError = nullptr ;
2332
+ ClassDecl *nsErrorDecl = nullptr ;
2333
+ ProtocolDecl *errorCodeProto = nullptr ;
2334
+ if (enumInfo.isErrorEnum () &&
2335
+ (bridgedNSError =
2336
+ C.getProtocol (KnownProtocolKind::BridgedStoredNSError)) &&
2337
+ (nsErrorDecl = C.getNSErrorDecl ()) &&
2338
+ (errorCodeProto =
2339
+ C.getProtocol (KnownProtocolKind::ErrorCodeProtocol))) {
2340
+ // Create the wrapper struct.
2341
+ errorWrapper = Impl.createDeclWithClangNode <StructDecl>(
2342
+ decl, loc, name, loc, None, nullptr , dc);
2343
+ errorWrapper->computeType ();
2344
+
2345
+ // Add inheritance clause.
2346
+ TypeLoc inheritedTypes[1 ] = {
2347
+ TypeLoc::withoutLoc (bridgedNSError->getDeclaredType ())
2348
+ };
2349
+ errorWrapper->setInherited (C.AllocateCopy (inheritedTypes));
2350
+ errorWrapper->setCheckedInheritanceClause ();
2351
+
2352
+ // Set up error conformance to be lazily expanded
2353
+ errorWrapper->getAttrs ().add (new (C) SynthesizedProtocolAttr (
2354
+ KnownProtocolKind::BridgedStoredNSError));
2355
+
2356
+ // Create the _nsError member.
2357
+ // public let _nsError: NSError
2358
+ auto nsErrorType = nsErrorDecl->getDeclaredInterfaceType ();
2359
+ auto nsErrorProp = new (C) VarDecl (/* static*/ false , /* IsLet*/ true ,
2360
+ loc, C.Id_nsError , nsErrorType,
2361
+ errorWrapper);
2362
+ nsErrorProp->setImplicit ();
2363
+ nsErrorProp->setAccessibility (Accessibility::Public);
2364
+
2365
+ // Create a pattern binding to describe the variable.
2366
+ Pattern *nsErrorPattern = createTypedNamedPattern (nsErrorProp);
2367
+
2368
+ auto nsErrorBinding = PatternBindingDecl::create (
2369
+ C, loc, StaticSpellingKind::None, loc,
2370
+ nsErrorPattern, nullptr , errorWrapper);
2371
+ errorWrapper->addMember (nsErrorProp);
2372
+ errorWrapper->addMember (nsErrorBinding);
2373
+
2374
+ // Create the _nsError initializer.
2375
+ // public init(_nsError error: NSError)
2376
+ VarDecl *members[1 ] = { nsErrorProp };
2377
+ auto nsErrorInit = createValueConstructor (errorWrapper, members,
2378
+ /* wantCtorParamNames=*/ true ,
2379
+ /* wantBody=*/ true );
2380
+ errorWrapper->addMember (nsErrorInit);
2381
+
2382
+ // Add the domain error member.
2383
+ // public static var _nsErrorDomain: String { return error-domain }
2384
+ addErrorDomain (errorWrapper, enumInfo.getErrorDomain (), Impl);
2385
+
2386
+ // Note: the Code will be added after it's created.
2387
+
2388
+ // The enum itself will be nested within the error wrapper,
2389
+ // and be named Code.
2390
+ enumDC = errorWrapper;
2391
+ enumName = C.Id_Code ;
2392
+ }
2393
+
2394
+ // Create the enumeration.
2315
2395
auto enumDecl = Impl.createDeclWithClangNode <EnumDecl>(
2316
- decl, Impl. importSourceLoc (decl-> getLocStart ()), name ,
2317
- Impl.importSourceLoc (decl->getLocation ()), None, nullptr , dc );
2396
+ decl, loc, enumName ,
2397
+ Impl.importSourceLoc (decl->getLocation ()), None, nullptr , enumDC );
2318
2398
enumDecl->computeType ();
2319
2399
2320
2400
// Set up the C underlying type as its Swift raw type.
@@ -2327,18 +2407,13 @@ namespace {
2327
2407
// Add protocol declarations to the enum declaration.
2328
2408
SmallVector<TypeLoc, 2 > inheritedTypes;
2329
2409
inheritedTypes.push_back (TypeLoc::withoutLoc (underlyingType));
2330
- if (enumInfo. isErrorEnum ())
2331
- inheritedTypes.push_back (TypeLoc::withoutLoc (
2332
- C. getProtocol (KnownProtocolKind::BridgedNSError)
2333
- -> getDeclaredType ()));
2410
+ if (errorWrapper) {
2411
+ inheritedTypes.push_back (
2412
+ TypeLoc::withoutLoc (errorCodeProto-> getDeclaredType ()));
2413
+ }
2334
2414
enumDecl->setInherited (C.AllocateCopy (inheritedTypes));
2335
2415
enumDecl->setCheckedInheritanceClause ();
2336
2416
2337
- // Set up error conformance to be lazily expanded
2338
- if (enumInfo.isErrorEnum ())
2339
- enumDecl->getAttrs ().add (new (C) SynthesizedProtocolAttr (
2340
- KnownProtocolKind::BridgedNSError));
2341
-
2342
2417
// Provide custom implementations of the init(rawValue:) and rawValue
2343
2418
// conversions that just do a bitcast. We can't reliably filter a
2344
2419
// C enum without additional knowledge that the type has no
@@ -2367,20 +2442,38 @@ namespace {
2367
2442
enumDecl->addMember (rawValueGetter);
2368
2443
enumDecl->addMember (rawValue);
2369
2444
enumDecl->addMember (rawValueBinding);
2370
- result = enumDecl;
2371
2445
2372
- // Add the domain error member
2373
- if (enumInfo.isErrorEnum ())
2374
- addErrorDomain (enumDecl, enumInfo.getErrorDomain (), Impl);
2446
+ // If we have an error wrapper, finish it up now that its
2447
+ // nested enum has been constructed.
2448
+ if (errorWrapper) {
2449
+ // Add the ErrorType alias:
2450
+ // public typealias ErrorType
2451
+ auto alias = Impl.createDeclWithClangNode <TypeAliasDecl>(
2452
+ decl, loc, C.Id_ErrorType , loc,
2453
+ TypeLoc::withoutLoc (
2454
+ errorWrapper->getDeclaredInterfaceType ()),
2455
+ /* genericSignature=*/ nullptr , enumDecl);
2456
+ alias->computeType ();
2457
+ enumDecl->addMember (alias);
2458
+
2459
+ // Add the 'Code' enum to the error wrapper.
2460
+ errorWrapper->addMember (enumDecl);
2461
+ result = errorWrapper;
2462
+ } else {
2463
+ result = enumDecl;
2464
+ }
2375
2465
2466
+ // The enumerators go into this enumeration.
2467
+ enumeratorContext = enumDecl;
2376
2468
break ;
2377
2469
}
2378
2470
2379
2471
case EnumKind::Options: {
2380
2472
result = importAsOptionSetType (dc, name, decl);
2381
2473
if (!result)
2382
2474
return nullptr ;
2383
-
2475
+
2476
+ enumeratorContext = result;
2384
2477
break ;
2385
2478
}
2386
2479
}
@@ -2412,31 +2505,50 @@ namespace {
2412
2505
break ;
2413
2506
case EnumKind::Options:
2414
2507
enumeratorDecl = SwiftDeclConverter (Impl, /* useSwift2Name=*/ false )
2415
- .importOptionConstant (*ec, decl, result);
2508
+ .importOptionConstant (*ec, decl,
2509
+ enumeratorContext);
2416
2510
swift2EnumeratorDecl = SwiftDeclConverter (Impl,/* useSwift2Name=*/ true )
2417
- .importOptionConstant (*ec, decl, result);
2511
+ .importOptionConstant (*ec, decl,
2512
+ enumeratorContext);
2418
2513
break ;
2419
2514
case EnumKind::Enum:
2420
2515
enumeratorDecl = SwiftDeclConverter (Impl, /* useSwift2Name=*/ false )
2421
- .importEnumCase (*ec, decl, cast<EnumDecl>(result));
2516
+ .importEnumCase (*ec, decl,
2517
+ cast<EnumDecl>(enumeratorContext));
2422
2518
swift2EnumeratorDecl = SwiftDeclConverter (Impl,/* useSwift2Name=*/ true )
2423
- .importEnumCase (*ec, decl,
2424
- cast<EnumDecl>(result),
2425
- enumeratorDecl);
2519
+ .importEnumCase (
2520
+ *ec, decl,
2521
+ cast<EnumDecl>(enumeratorContext),
2522
+ enumeratorDecl);
2426
2523
break ;
2427
2524
}
2428
2525
if (!enumeratorDecl)
2429
2526
continue ;
2430
2527
2431
2528
if (addEnumeratorsAsMembers) {
2432
- result->addMember (enumeratorDecl);
2433
- if (auto *var = dyn_cast<VarDecl>(enumeratorDecl))
2434
- result->addMember (var->getGetter ());
2435
-
2436
- if (swift2EnumeratorDecl) {
2437
- result->addMember (swift2EnumeratorDecl);
2438
- if (auto *var = dyn_cast<VarDecl>(swift2EnumeratorDecl))
2439
- result->addMember (var->getGetter ());
2529
+ // Add a member enumerator to the given nominal type.
2530
+ auto addDecl = [&](NominalTypeDecl *nominal, Decl *decl) {
2531
+ if (!decl) return ;
2532
+ nominal->addMember (decl);
2533
+ if (auto *var = dyn_cast<VarDecl>(decl))
2534
+ nominal->addMember (var->getGetter ());
2535
+ };
2536
+
2537
+ addDecl (enumeratorContext, enumeratorDecl);
2538
+ addDecl (enumeratorContext, swift2EnumeratorDecl);
2539
+
2540
+ // If there is an error wrapper, add an alias within the
2541
+ // wrapper to the corresponding value within the enumerator
2542
+ // context.
2543
+ if (errorWrapper) {
2544
+ auto enumeratorValue = cast<ValueDecl>(enumeratorDecl);
2545
+ auto alias = importEnumCaseAlias (enumeratorValue->getName (),
2546
+ *ec,
2547
+ enumeratorValue,
2548
+ decl,
2549
+ enumeratorContext,
2550
+ result);
2551
+ addDecl (result, alias);
2440
2552
}
2441
2553
}
2442
2554
}
@@ -2445,6 +2557,8 @@ namespace {
2445
2557
// raw values and SILGen can emit witness tables for derived conformances.
2446
2558
// FIXME: There might be better ways to do this.
2447
2559
Impl.registerExternalDecl (result);
2560
+ if (result != enumeratorContext)
2561
+ Impl.registerExternalDecl (enumeratorContext);
2448
2562
return result;
2449
2563
}
2450
2564
0 commit comments