text: //===--- TypeCheckType.cpp - Type Validation ------------------------------===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See http://swift.org/LICENSE.txt for license information
  // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  // This file implements validation for Swift types, emitting semantic errors as
  // appropriate and checking default initializer values.
  //
  //===----------------------------------------------------------------------===//
  
  #include "TypeChecker.h"
  #include "GenericTypeResolver.h"
  
  #include "swift/Strings.h"
  #include "swift/AST/ASTVisitor.h"
  #include "swift/AST/ASTWalker.h"
  #include "swift/AST/ExprHandle.h"
  #include "swift/AST/ForeignErrorConvention.h"
  #include "swift/AST/NameLookup.h"
  #include "swift/AST/PrettyStackTrace.h"
  #include "swift/AST/TypeLoc.h"
  #include "swift/Basic/SourceManager.h"
  #include "swift/Basic/StringExtras.h"
  #include "swift/ClangImporter/ClangImporter.h"
  #include "llvm/ADT/APInt.h"
  #include "llvm/ADT/SmallString.h"
  #include "llvm/ADT/StringSwitch.h"
  #include "llvm/ADT/Twine.h"
  using namespace swift;
  
  GenericTypeResolver::~GenericTypeResolver() { }
  
  Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) {
    if (!Context.getArrayDecl()) {
      diagnose(loc, diag::sugar_type_not_found, 0);
      return Type();
    }
  
    return ArraySliceType::get(elementType);
  }
  
  Type TypeChecker::getDictionaryType(SourceLoc loc, Type keyType, 
                                      Type valueType) {
    if (!Context.getDictionaryDecl()) {
      diagnose(loc, diag::sugar_type_not_found, 3);
      return Type();
    }
  
      return DictionaryType::get(keyType, valueType);
  }
  
  Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) {
    if (!Context.getOptionalDecl()) {
      diagnose(loc, diag::sugar_type_not_found, 1);
      return Type();
    }
  
    return OptionalType::get(elementType);
  }
  
  Type TypeChecker::getImplicitlyUnwrappedOptionalType(SourceLoc loc, Type elementType) {
    if (!Context.getImplicitlyUnwrappedOptionalDecl()) {
      diagnose(loc, diag::sugar_type_not_found, 2);
      return Type();
    }
  
    return ImplicitlyUnwrappedOptionalType::get(elementType);
  }
  
  static Type getStdlibType(TypeChecker &TC, Type &cached, DeclContext *dc,
                            StringRef name) {
    if (cached.isNull()) {
      Module *stdlib = TC.Context.getStdlibModule();
      LookupTypeResult lookup = TC.lookupMemberType(dc, ModuleType::get(stdlib),
                                                    TC.Context.getIdentifier(
                                                      name));
      if (lookup)
        cached = lookup.back().second;
    }
    return cached;
  }
  
  Type TypeChecker::getStringType(DeclContext *dc) {
    return ::getStdlibType(*this, StringType, dc, "String");
  }
  Type TypeChecker::getInt8Type(DeclContext *dc) {
    return ::getStdlibType(*this, Int8Type, dc, "Int8");
  }
  Type TypeChecker::getUInt8Type(DeclContext *dc) {
    return ::getStdlibType(*this, UInt8Type, dc, "UInt8");
  }
  
  /// Find the standard type of exceptions.
  ///
  /// We call this the "exception type" to try to avoid confusion with
  /// the AST's ErrorType node.
  Type TypeChecker::getExceptionType(DeclContext *dc, SourceLoc loc) {
    if (NominalTypeDecl *decl = Context.getExceptionTypeDecl())
      return decl->getDeclaredType();
  
    // Not really sugar, but the actual diagnostic text is fine.
    diagnose(loc, diag::sugar_type_not_found, 4);
    return Type();
  }
  
  static Type getObjectiveCClassType(TypeChecker &TC,
                                     Type &cache,
                                     Identifier ModuleName,
                                     Identifier TypeName,
                                     DeclContext *dc) {
    if (cache)
      return cache;
  
    auto &Context = TC.Context;
  
    // FIXME: Does not respect visibility of the module.
    Module *module = Context.getLoadedModule(ModuleName);
    if (!module)
      return nullptr;
  
    NameLookupOptions lookupOptions
      = defaultMemberLookupOptions | NameLookupFlags::KnownPrivate;
    if (auto result = TC.lookupMember(dc, ModuleType::get(module), TypeName,
                                      lookupOptions)) {
      for (auto decl : result) {
        if (auto nominal = dyn_cast<NominalTypeDecl>(decl.Decl)) {
          cache = nominal->getDeclaredType();
          return cache;
        }
      }
    }
  
    return nullptr;
  }
  
  Type TypeChecker::getNSObjectType(DeclContext *dc) {
    return getObjectiveCClassType(*this, NSObjectType, Context.Id_ObjectiveC,
                                  Context.Id_NSObject, dc);
  }
  
  Type TypeChecker::getNSErrorType(DeclContext *dc) {
    return getObjectiveCClassType(*this, NSObjectType, Context.Id_Foundation,
                                  Context.Id_NSError, dc);
  }
  
  Type TypeChecker::getBridgedToObjC(const DeclContext *dc, Type type) {
    if (auto bridged = Context.getBridgedToObjC(dc, type, this))
      return *bridged;
    return nullptr;
  }
  
  Type
  TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc,
                                                 Type dynamicType,
                                                 Type valueType) {
    // We can only bridge from class or Objective-C existential types.
    if (!dynamicType->isObjCExistentialType() &&
        !dynamicType->getClassOrBoundGenericClass())
      return Type();
  
    // If the value type canot be bridged, we're done.
    if (!valueType->isPotentiallyBridgedValueType())
      return Type();
  
    return getBridgedToObjC(dc, valueType);
  }
  
  void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) {
    // Force any delayed members added to the nominal type declaration.
    if (nominalDecl->hasDelayedMemberDecls()) {
      nominalDecl->forceDelayed();
    }
    
    if (nominalDecl->hasDelayedMembers()) {
      this->handleExternalDecl(nominalDecl);
      nominalDecl->setHasDelayedMembers(false);
    }
  }
  
  Type TypeChecker::resolveTypeInContext(
         TypeDecl *typeDecl,
         DeclContext *fromDC,
         TypeResolutionOptions options,
         bool isSpecialized,
         GenericTypeResolver *resolver,
         UnsatisfiedDependency *unsatisfiedDependency) {
    PartialGenericTypeToArchetypeResolver defaultResolver(*this);
    if (!resolver)
      resolver = &defaultResolver;
  
    // If we have a callback to report dependencies, do so.
    if (unsatisfiedDependency &&
        (*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
      return nullptr;
  
    // If we found a generic parameter, map to the archetype if there is one.
    if (auto genericParam = dyn_cast<GenericTypeParamDecl>(typeDecl)) {
      return resolver->resolveGenericTypeParamType(
               genericParam->getDeclaredType()->castTo<GenericTypeParamType>());
    }
  
    // If we are referring to a type within its own context, and we have either
    // a generic type with no generic arguments or a non-generic type, use the
    // type within the context.
    if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) {
      
      this->forceExternalDeclMembers(nominal);
      
      if (!nominal->getGenericParams() || !isSpecialized) {
        for (DeclContext *dc = fromDC; dc; dc = dc->getParent()) {
          switch (dc->getContextKind()) {
          case DeclContextKind::Module:
          case DeclContextKind::FileUnit:
          case DeclContextKind::TopLevelCodeDecl:
          case DeclContextKind::Initializer:
            break;
  
          case DeclContextKind::NominalTypeDecl:
            // If this is our nominal type, return its type within its context.
            // FIXME: Just produce the type structure when TR_ResolveStructure.
            if (cast<NominalTypeDecl>(dc) == nominal)
              return resolver->resolveTypeOfContext(nominal);
            continue;
              
          case DeclContextKind::ExtensionDecl:
            // If this is an extension of our nominal type, return the type
            // within the context of its extension.
            // FIXME: Just produce the type structure when TR_ResolveStructure.
            if (cast<ExtensionDecl>(dc)->getExtendedType()->getAnyNominal()
                  == nominal)
              return resolver->resolveTypeOfContext(dc);
            continue;
  
          case DeclContextKind::AbstractClosureExpr:
          case DeclContextKind::AbstractFunctionDecl:
            continue;
          case DeclContextKind::SerializedLocal:
            llvm_unreachable("should not be typechecking deserialized things");
          }
  
          break;
        }
      }
    }
  
    // If the type declaration itself is in a non-type context, no type
    // substitution is needed.
    DeclContext *ownerDC = typeDecl->getDeclContext();
    if (!ownerDC->isTypeContext()) {
      // FIXME: Just produce the type structure when TR_ResolveStructure.
      return typeDecl->getDeclaredType();
    }
  
    // Find the nearest enclosing type context around the context from which
    // we started our search.
    while (!fromDC->isTypeContext()) {
      fromDC = fromDC->getParent();
      assert(!fromDC->isModuleContext());
    }
  
    // If we found an associated type in an inherited protocol, the base
    // for our reference to this associated type is our own 'Self'.
    auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl);
    if (assocType) {
      // If we found an associated type from within its protocol, resolve it
      // as a dependent member relative to Self if Self is still dependent.
      if (fromDC->isProtocolOrProtocolExtensionContext()) {
        auto selfTy = fromDC->getProtocolSelf()->getDeclaredType()
                        ->castTo<GenericTypeParamType>();
        auto baseTy = resolver->resolveGenericTypeParamType(selfTy);
  
        if (baseTy->isTypeParameter()) {
          return resolver->resolveSelfAssociatedType(baseTy, fromDC, assocType);
        }
      }
  
      if (typeDecl->getDeclContext() != fromDC) {
        if (fromDC->isProtocolOrProtocolExtensionContext()) {
          return substMemberTypeWithBase(fromDC->getParentModule(),
                                         typeDecl,
                                         fromDC->getProtocolSelf()
                                           ->getArchetype(),
                                         /*isTypeReference=*/true);
        }
      }
    }
  
    // Walk up through the type scopes to find the context where the type
    // declaration was found. When we find it, substitute the appropriate base
    // type.
    auto ownerNominal = ownerDC->isNominalTypeOrNominalTypeExtensionContext();
    assert(ownerNominal && "Owner must be a nominal type");
    for (auto parentDC = fromDC; !parentDC->isModuleContext();
         parentDC = parentDC->getParent()) {
      // Skip non-type contexts.
      if (!parentDC->isTypeContext())
        continue;
  
      // Search the type of this context and its supertypes.
      for (auto fromType = resolver->resolveTypeOfContext(parentDC);
           fromType;
           fromType = getSuperClassOf(fromType)) {
        // If the nominal type declaration of the context type we're looking at
        // matches the owner's nominal type declaration, this is how we found
        // the member type declaration. Substitute the type we're coming from as
        // the base of the member type to produce the projected type result.
        if (fromType->getAnyNominal() == ownerNominal) {
          // If we are referring into a protocol or extension thereof,
          // the base type is the 'Self'.
          if (ownerDC->isProtocolOrProtocolExtensionContext()) {
            auto selfTy = ownerDC->getProtocolSelf()->getDeclaredType()
                            ->castTo<GenericTypeParamType>();
            fromType = resolver->resolveGenericTypeParamType(selfTy);
          }
  
          // Perform the substitution.
          return substMemberTypeWithBase(parentDC->getParentModule(), typeDecl,
                                         fromType, /*isTypeReference=*/true);
        }
  
        ProtocolConformance *conformance = nullptr;
        if (assocType &&
            !options.contains(TR_InheritanceClause) &&
            conformsToProtocol(fromType,
                               cast<ProtocolDecl>(assocType->getDeclContext()),
                               parentDC, ConformanceCheckFlags::Used,
                               &conformance) &&
            conformance) {
          return conformance->getTypeWitness(assocType, this).getReplacement();
        }
      }
    }
  
    // Substitute in the appropriate type for 'Self'.
    // FIXME: We shouldn't have to guess here; the caller should tell us.
    Type fromType;
    if (fromDC->isProtocolOrProtocolExtensionContext())
      fromType = fromDC->getProtocolSelf()->getArchetype();
    else
      fromType = resolver->resolveTypeOfContext(fromDC);
  
    // Perform the substitution.
    return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl,
                                   fromType, /*isTypeReference=*/true);
  }
  
  /// Apply generic arguments to the given type.
  Type TypeChecker::applyGenericArguments(Type type,
                                          SourceLoc loc,
                                          DeclContext *dc,
                                          MutableArrayRef<TypeLoc> genericArgs,
                                          bool isGenericSignature,
                                          GenericTypeResolver *resolver) {
    // Make sure we always have a resolver to use.
    PartialGenericTypeToArchetypeResolver defaultResolver(*this);
    if (!resolver)
      resolver = &defaultResolver;
  
    auto unbound = type->getAs<UnboundGenericType>();
    if (!unbound) {
      // FIXME: Highlight generic arguments and introduce a Fix-It to remove
      // them.
      diagnose(loc, diag::not_a_generic_type, type);
  
      // Just return the type; this provides better recovery anyway.
      return type;
    }
  
    // Make sure we have the right number of generic arguments.
    // FIXME: If we have fewer arguments than we need, that might be okay, if
    // we're allowed to deduce the remaining arguments from context.
    auto genericParams = unbound->getDecl()->getGenericParams();
    if (genericParams->size() != genericArgs.size()) {
      // FIXME: Highlight <...>.
      diagnose(loc, diag::type_parameter_count_mismatch,
               unbound->getDecl()->getName(),
               genericParams->size(), genericArgs.size(),
               genericArgs.size() < genericParams->size());
      diagnose(unbound->getDecl(), diag::generic_type_declared_here,
               unbound->getDecl()->getName());
      return nullptr;
    }
  
    TypeResolutionOptions options;
    if (isGenericSignature)
      options |= TR_GenericSignature;
  
    // Validate the generic arguments and capture just the types.
    SmallVector<Type, 4> genericArgTypes;
    for (auto &genericArg : genericArgs) {
      // Validate the generic argument.
      if (validateType(genericArg, dc, options, resolver))
        return nullptr;
  
      genericArgTypes.push_back(genericArg.getType());
    }
  
    // Form the bound generic type
    BoundGenericType *BGT = BoundGenericType::get(unbound->getDecl(),
                                                  unbound->getParent(),
                                                  genericArgTypes);
    // Check protocol conformance.
    if (!BGT->hasTypeParameter()) {
      SourceLoc noteLoc = unbound->getDecl()->getLoc();
      if (noteLoc.isInvalid())
        noteLoc = loc;
  
      // FIXME: Record that we're checking substitutions, so we can't end up
      // with infinite recursion.
  
      // Collect the complete set of generic arguments.
      SmallVector<Type, 4> scratch;
      ArrayRef<Type> allGenericArgs = BGT->getAllGenericArgs(scratch);
  
      // Check the generic arguments against the generic signature.
      auto genericSig = unbound->getDecl()->getGenericSignature();
      if (unbound->getDecl()->IsValidatingGenericSignature()) {
        diagnose(loc, diag::recursive_requirement_reference);
        return BGT;
      }
      assert(genericSig != nullptr);
      if (checkGenericArguments(dc, loc, noteLoc, unbound, genericSig,
                                allGenericArgs))
        return nullptr;
    }
  
    return BGT;
  }
  
  static Type applyGenericTypeReprArgs(TypeChecker &TC, Type type, SourceLoc loc,
                                       DeclContext *dc,
                                       ArrayRef<TypeRepr *> genericArgs,
                                       bool isGenericSignature,
                                       GenericTypeResolver *resolver) {
    SmallVector<TypeLoc, 8> args;
    for (auto tyR : genericArgs)
      args.push_back(tyR);
    Type ty = TC.applyGenericArguments(type, loc, dc, args,
                                       isGenericSignature, resolver);
    if (!ty)
      return ErrorType::get(TC.Context);
    return ty;
  }
  
  
  /// \brief Diagnose a use of an unbound generic type.
  static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) {
    tc.diagnose(loc, diag::generic_type_requires_arguments, ty);
    auto unbound = ty->castTo<UnboundGenericType>();
    tc.diagnose(unbound->getDecl()->getLoc(), diag::generic_type_declared_here,
                unbound->getDecl()->getName());
  }
  
  /// \brief Returns a valid type or ErrorType in case of an error.
  static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc,
                              DeclContext *dc,
                              ArrayRef<TypeRepr *> genericArgs,
                              TypeResolutionOptions options,
                              GenericTypeResolver *resolver,
                              UnsatisfiedDependency *unsatisfiedDependency) {
    assert(dc && "No declaration context for type resolution?");
  
    // If we have a callback to report dependencies, do so.
    if (unsatisfiedDependency) {
      if ((*unsatisfiedDependency)(requestResolveTypeDecl(typeDecl)))
        return nullptr;
    } else {
      // Validate the declaration.
      TC.validateDecl(typeDecl);
    }
  
    // Resolve the type declaration to a specific type. How this occurs
    // depends on the current context and where the type was found.
    Type type = TC.resolveTypeInContext(typeDecl, dc, options,
                                        !genericArgs.empty(), resolver);
  
    // FIXME: Defensive check that shouldn't be needed, but prevents a
    // huge number of crashes on ill-formed code.
    if (!type)
      return ErrorType::get(TC.Context);
  
    if (type->is<UnboundGenericType>() && genericArgs.empty() &&
        !options.contains(TR_AllowUnboundGenerics) &&
        !options.contains(TR_ResolveStructure)) {
      diagnoseUnboundGenericType(TC, type, loc);
      return ErrorType::get(TC.Context);
    }
  
    // If we found a generic parameter, try to resolve it.
    // FIXME: Jump through hoops to maintain syntactic sugar. We shouldn't care
    // about this, because we shouldn't have to do this at all.
    if (auto genericParam = type->getAs<GenericTypeParamType>()) {
      auto resolvedGP = resolver->resolveGenericTypeParamType(genericParam);
      if (auto substituted = dyn_cast<SubstitutedType>(type.getPointer())) {
        type = SubstitutedType::get(substituted->getOriginal(), resolvedGP,
                                    TC.Context);
      } else {
        type = resolvedGP;
      }
    }
  
    if (!genericArgs.empty() && !options.contains(TR_ResolveStructure)) {
      // Apply the generic arguments to the type.
      type = applyGenericTypeReprArgs(TC, type, loc, dc, genericArgs,
                                      options.contains(TR_GenericSignature),
                                      resolver);
    }
  
    assert(type);
    return type;
  }
  
  /// Retrieve the nearest enclosing nominal type context.
  static NominalTypeDecl *getEnclosingNominalContext(DeclContext *dc) {
    while (dc->isLocalContext())
      dc = dc->getParent();
  
    if (auto nominal = dc->isNominalTypeOrNominalTypeExtensionContext())
      return nominal;
  
    return nullptr;
  }
  
  /// Diagnose a reference to an unknown type.
  ///
  /// This routine diagnoses a reference to an unknown type, and
  /// attempts to fix the reference via various means.
  ///
  /// \param tc The type checker through which we should emit the diagnostic.
  /// \param dc The context in which name lookup occurred.
  ///
  /// \returns either the corrected type, if possible, or an error type to
  /// that correction failed.
  static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc,
                                  Type parentType,
                                  SourceRange parentRange,
                                  ComponentIdentTypeRepr *comp,
                                  TypeResolutionOptions options,
                                  GenericTypeResolver *resolver,
                                  UnsatisfiedDependency *unsatisfiedDependency) {
    // Unqualified lookup case.
    if (parentType.isNull()) {
      // Attempt to refer to 'Self' within a non-protocol nominal
      // type. Fix this by replacing 'Self' with the nominal type name.
      NominalTypeDecl *nominal = nullptr;
      if (comp->getIdentifier() == tc.Context.Id_Self &&
          !isa<GenericIdentTypeRepr>(comp) &&
          (nominal = getEnclosingNominalContext(dc))) {
        // Retrieve the nominal type and resolve it within this context.
        assert(!isa<ProtocolDecl>(nominal) && "Cannot be a protocol");
        auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, { },
                                    options, resolver, unsatisfiedDependency);
        if (type->is<ErrorType>())
          return type;
  
        // Produce a Fix-It replacing 'Self' with the nominal type name.
        tc.diagnose(comp->getIdLoc(), diag::self_in_nominal, nominal->getName())
          .fixItReplace(comp->getIdLoc(), nominal->getName().str());
        comp->overwriteIdentifier(nominal->getName());
        comp->setValue(nominal);
        return type;
      }
      
      // Fallback.
      SourceLoc L = comp->getIdLoc();
      SourceRange R = SourceRange(comp->getIdLoc());
  
      // Check if the unknown type is in the type remappings.
      auto &Remapped = tc.Context.RemappedTypes;
      auto TypeName = comp->getIdentifier().str();
      auto I = Remapped.find(TypeName);
      if (I != Remapped.end()) {
        auto RemappedTy = I->second->getString();
        tc.diagnose(L, diag::use_undeclared_type_did_you_mean,
                    comp->getIdentifier(), RemappedTy)
          .highlight(R)
          .fixItReplace(R, RemappedTy);
  
        // Replace the computed type with the suggested type.
        comp->overwriteIdentifier(tc.Context.getIdentifier(RemappedTy));
  
        // HACK: 'NSUInteger' suggests both 'UInt' and 'Int'.
        if (TypeName == "NSUInteger") {
          tc.diagnose(L, diag::note_remapped_type, "UInt")
            .fixItReplace(R, "UInt");
        }
  
        return I->second;
      }
  
      tc.diagnose(L, diag::use_undeclared_type,
                  comp->getIdentifier())
        .highlight(R);
  
      return ErrorType::get(tc.Context);
    }
  
    // Qualified lookup case.
    // FIXME: Typo correction!
  
    // Lookup into a type.
    if (auto moduleType = parentType->getAs<ModuleType>()) {
      tc.diagnose(comp->getIdLoc(), diag::no_module_type,
                  comp->getIdentifier(), moduleType->getModule()->getName());
    } else {
      tc.diagnose(comp->getIdLoc(), diag::invalid_member_type,
                  comp->getIdentifier(), parentType)
        .highlight(parentRange);
    }
  
    return ErrorType::get(tc.Context);
  }
  
  /// Resolve the given identifier type representation as an unqualified type,
  /// returning the type it references.
  ///
  /// \returns Either the resolved type or a null type, the latter of
  /// which indicates that some dependencies were unsatisfied.
  static Type
  resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
                                    ComponentIdentTypeRepr *comp,
                                    TypeResolutionOptions options,
                                    bool diagnoseErrors,
                                    GenericTypeResolver *resolver,
                                    UnsatisfiedDependency *unsatisfiedDependency){
    // Short-circuiting.
    if (comp->isInvalid()) return ErrorType::get(TC.Context);
  
    // If the component has already been bound to a declaration, handle
    // that now.
    if (ValueDecl *VD = comp->getBoundDecl()) {
      // Diagnose non-type declarations.
      auto typeDecl = dyn_cast<TypeDecl>(VD);
      if (!typeDecl) {
        if (diagnoseErrors) {
          TC.diagnose(comp->getIdLoc(), diag::use_non_type_value, VD->getName());
          TC.diagnose(VD, diag::use_non_type_value_prev, VD->getName());
        }
  
        comp->setInvalid();
        return ErrorType::get(TC.Context);
      }
  
      // Retrieve the generic arguments, if there are any.
      ArrayRef<TypeRepr *> genericArgs;
      if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
        genericArgs = genComp->getGenericArgs();
  
      // Resolve the type declaration within this context.
      return resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), DC,
                             genericArgs, options, resolver,
                             unsatisfiedDependency);
    }
  
    // Resolve the first component, which is the only one that requires
    // unqualified name lookup.
    DeclContext *lookupDC = DC;
  
    // Dynamic 'Self' in the result type of a function body.
    if (options.contains(TR_DynamicSelfResult) &&
        comp->getIdentifier() == TC.Context.Id_Self) {
      auto func = cast<FuncDecl>(DC);
      assert(func->hasDynamicSelf() && "Not marked as having dynamic Self?");
  
      return func->getDynamicSelf();
    }
  
    // For lookups within the generic signature, look at the generic
    // parameters (only), then move up to the enclosing context.
    if (options.contains(TR_GenericSignature)) {
      GenericParamList *genericParams;
      if (auto *nominal = dyn_cast<NominalTypeDecl>(DC)) {
        genericParams = nominal->getGenericParams();
      } else if (auto *ext = dyn_cast<ExtensionDecl>(DC)) {
        genericParams = ext->getGenericParams();
      } else {
        genericParams = cast<AbstractFunctionDecl>(DC)->getGenericParams();
      }
  
      if (genericParams) {
        auto matchingParam =
            std::find_if(genericParams->begin(), genericParams->end(),
                         [comp](const GenericTypeParamDecl *param) {
          return param->getFullName().matchesRef(comp->getIdentifier());
        });
  
        if (matchingParam != genericParams->end()) {
          comp->setValue(*matchingParam);
          return resolveTopLevelIdentTypeComponent(TC, DC, comp, options,
                                                   diagnoseErrors, resolver,
                                                   unsatisfiedDependency);
        }
      }
  
      // If the lookup occurs from within a trailing 'where' clause of
      // a constrained extension, also look for associated types.
      if (genericParams && genericParams->hasTrailingWhereClause() &&
          isa<ExtensionDecl>(DC) && comp->getIdLoc().isValid() &&
          TC.Context.SourceMgr.rangeContainsTokenLoc(
            genericParams->getTrailingWhereClauseSourceRange(),
            comp->getIdLoc())) {
        // We need to be able to perform qualified lookup into the given
        // declaration context.
        if (unsatisfiedDependency &&
            (*unsatisfiedDependency)(
              requestQualifiedLookupInDeclContext({ DC, comp->getIdentifier(),
                                                    comp->getIdLoc() })))
          return nullptr;
  
        auto nominal = DC->isNominalTypeOrNominalTypeExtensionContext();
        SmallVector<ValueDecl *, 4> decls;
        if (DC->lookupQualified(nominal->getDeclaredInterfaceType(),
                                comp->getIdentifier(),
                                NL_QualifiedDefault|NL_ProtocolMembers,
                                &TC,
                                decls)) {
          for (const auto decl : decls) {
            // FIXME: Better ambiguity handling.
            if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
              comp->setValue(assocType);
              return resolveTopLevelIdentTypeComponent(TC, DC, comp, options,
                                                       diagnoseErrors, resolver,
                                                       unsatisfiedDependency);
            }
          }
        }
      }
  
      if (!DC->isCascadingContextForLookup(/*excludeFunctions*/true))
        options |= TR_KnownNonCascadingDependency;
  
      // The remaining lookups will be in the parent context.
      lookupDC = DC->getParent();
    }
  
    // We need to be able to perform unqualified lookup into the given
    // declaration context.
    if (unsatisfiedDependency &&
        (*unsatisfiedDependency)(
          requestUnqualifiedLookupInDeclContext({ lookupDC, 
                                                  comp->getIdentifier(),
                                                  comp->getIdLoc() })))
      return nullptr;
  
    NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions;
    lookupOptions |= NameLookupFlags::OnlyTypes;
    if (options.contains(TR_KnownNonCascadingDependency))
      lookupOptions |= NameLookupFlags::KnownPrivate;
    // FIXME: Eliminate this once we can handle finding protocol members
    // in resolveTypeInContext.
    lookupOptions -= NameLookupFlags::ProtocolMembers;
    LookupResult globals = TC.lookupUnqualified(lookupDC, comp->getIdentifier(),
                                                comp->getIdLoc(), lookupOptions);
  
    // Process the names we found.
    Type current;
    TypeDecl *currentDecl = nullptr;
    bool isAmbiguous = false;
    for (const auto &result : globals) {
      // Ignore non-type declarations.
      auto typeDecl = dyn_cast<TypeDecl>(result.Decl);
      if (!typeDecl)
        continue;
      
      // If necessary, add delayed members to the declaration.
      if (auto nomDecl = dyn_cast<NominalTypeDecl>(typeDecl)) {
        TC.forceExternalDeclMembers(nomDecl);
      }
  
      ArrayRef<TypeRepr *> genericArgs;
      if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
        genericArgs = genComp->getGenericArgs();
      Type type = resolveTypeDecl(TC, typeDecl, comp->getIdLoc(),
                                  DC, genericArgs, options, resolver,
                                  unsatisfiedDependency);
      if (!type || type->is<ErrorType>())
        return type;
  
      // If this is the first result we found, record it.
      if (current.isNull()) {
        current = type;
        currentDecl = typeDecl;
        continue;
      }
  
      // Otherwise, check for an ambiguity.
      if (!current->isEqual(type)) {
        isAmbiguous = true;
        break;
      }
  
      // We have a found multiple type aliases that refer to the same thing.
      // Ignore the duplicate.
    }
  
    // Complain about any ambiguities we detected.
    // FIXME: We could recover by looking at later components.
    if (isAmbiguous) {
      if (diagnoseErrors) {
        TC.diagnose(comp->getIdLoc(), diag::ambiguous_type_base,
                    comp->getIdentifier())
          .highlight(comp->getIdLoc());
        for (auto result : globals) {
          TC.diagnose(result.Decl, diag::found_candidate);
        }
      }
  
      comp->setInvalid();
      return ErrorType::get(TC.Context);
    }
  
    // If we found nothing, complain and give ourselves a chance to recover.
    if (current.isNull()) {
      // If we're not allowed to complain or we couldn't fix the
      // source, bail out.
      if (!diagnoseErrors)
        return ErrorType::get(TC.Context);
  
      return diagnoseUnknownType(TC, DC, nullptr, SourceRange(), comp, options,
                                 resolver, unsatisfiedDependency);
    }
  
    comp->setValue(currentDecl);
    return current;
  }
  
  /// Resolve the given identifier type representation as a qualified
  /// lookup within the given parent type, returning the type it
  /// references.
  static Type resolveNestedIdentTypeComponent(
                TypeChecker &TC, DeclContext *DC,
                Type parentTy,
                SourceRange parentRange,
                ComponentIdentTypeRepr *comp,
                TypeResolutionOptions options,
                bool diagnoseErrors,
                GenericTypeResolver *resolver,
                UnsatisfiedDependency *unsatisfiedDependency) {
    // Short-circuiting.
    if (comp->isInvalid()) return ErrorType::get(TC.Context);
  
    // If a declaration has already been bound, use it.
    if (ValueDecl *decl = comp->getBoundDecl()) {
      // Make sure we have a type declaration.
      auto typeDecl = dyn_cast<TypeDecl>(decl);
      if (!typeDecl) {
        if (diagnoseErrors) {
          TC.diagnose(comp->getIdLoc(), diag::use_non_type_value,
                      decl->getName());
          TC.diagnose(decl, diag::use_non_type_value_prev,
                      decl->getName());
        }
  
        comp->setInvalid();
        return ErrorType::get(TC.Context);
      }
  
      Type memberType;
  
      if (parentTy->isTypeParameter()) {
        // If the parent is a type parameter, the member is a dependent member.
  
        // FIXME: We either have an associated type here or a member of
        // some member of the superclass bound (or its superclasses),
        // which should allow us to skip much of the work in
        // resolveDependentMemberType.
  
        // Try to resolve the dependent member type to a specific associated
        // type.
        memberType = resolver->resolveDependentMemberType(parentTy, DC,
                                                          parentRange, comp);
        assert(memberType && "Received null dependent member type");
      } else if (isa<AssociatedTypeDecl>(typeDecl) &&
                 !parentTy->is<ArchetypeType>() &&
                 !parentTy->isExistentialType()) {
        auto assocType = cast<AssociatedTypeDecl>(typeDecl);
  
        // Find the conformance and dig out the type witness.
        ConformanceCheckOptions conformanceOptions;
        if (options.contains(TR_InExpression))
          conformanceOptions |= ConformanceCheckFlags::InExpression;
  
        auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext());
        ProtocolConformance *conformance = nullptr;
        if (!TC.conformsToProtocol(parentTy, protocol, DC, conformanceOptions,
                                   &conformance) ||
            !conformance) {
          return nullptr;
        }
  
        // FIXME: Establish that we need a type witness.
        return conformance->getTypeWitness(assocType, &TC).getReplacement();
      } else {
        // Otherwise, simply substitute the parent type into the member.
        memberType = TC.substMemberTypeWithBase(DC->getParentModule(), typeDecl,
                                                parentTy,
                                                /*isTypeReference=*/true);
      }
  
      // Propagate failure.
      if (!memberType || memberType->is<ErrorType>()) return memberType;
  
      // If there are generic arguments, apply them now.
      if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp)) {
        memberType = applyGenericTypeReprArgs(
                       TC, memberType, comp->getIdLoc(), DC,
                       genComp->getGenericArgs(),
                       options.contains(TR_GenericSignature),
                       resolver);
  
        // Propagate failure.
        if (!memberType || memberType->is<ErrorType>()) return memberType;
      }
  
      // We're done.
      return memberType;
    }
  
    // If the parent is a dependent type, the member is a dependent member.
    if (parentTy->isTypeParameter()) {
      // Try to resolve the dependent member type to a specific associated
      // type.
      Type memberType = resolver->resolveDependentMemberType(parentTy, DC,
                                                             parentRange,
                                                             comp);
      assert(memberType && "Received null dependent member type");
  
      if (isa<GenericIdentTypeRepr>(comp) && !memberType->is<ErrorType>()) {
        // FIXME: Highlight generic arguments and introduce a Fix-It to
        // remove them.
        if (diagnoseErrors)
          TC.diagnose(comp->getIdLoc(), diag::not_a_generic_type, memberType);
  
        // Drop the arguments.
      }
  
      // If we know what type declaration we're referencing, store it.
      if (auto typeDecl = memberType->getDirectlyReferencedTypeDecl()) {
        comp->setValue(typeDecl);
      }
  
      return memberType;
    }
  
    // Look for member types with the given name.
    bool isKnownNonCascading = options.contains(TR_KnownNonCascadingDependency);
    if (!isKnownNonCascading && options.contains(TR_InExpression)) {
      // Expressions cannot affect a function's signature.
      isKnownNonCascading = isa<AbstractFunctionDecl>(DC);
    }
  
    // We need to be able to perform qualified lookup into the given type.
    if (unsatisfiedDependency) {
      DeclContext *dc;
      if (auto parentNominal = parentTy->getAnyNominal())
        dc = parentNominal;
      else if (auto parentModule = parentTy->getAs<ModuleType>())
        dc = parentModule->getModule();
      else
        dc = nullptr;
  
      if (dc &&
          (*unsatisfiedDependency)(
            requestQualifiedLookupInDeclContext({ dc, comp->getIdentifier(),
                                                  comp->getIdLoc() })))
        return nullptr;
    }
  
    NameLookupOptions lookupOptions = defaultMemberLookupOptions;
    if (isKnownNonCascading)
      lookupOptions |= NameLookupFlags::KnownPrivate;
    if (options.contains(TR_ExtensionBinding))
      lookupOptions -= NameLookupFlags::ProtocolMembers;
    auto memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(),
                                           lookupOptions);
  
    // Name lookup was ambiguous. Complain.
    // FIXME: Could try to apply generic arguments first, and see whether
    // that resolves things. But do we really want that to succeed?
    if (memberTypes.size() > 1) {
      if (diagnoseErrors)
        TC.diagnoseAmbiguousMemberType(parentTy, parentRange,
                                       comp->getIdentifier(), comp->getIdLoc(),
                                       memberTypes);
      return ErrorType::get(TC.Context);
    }
  
    // If we didn't find anything, complain.
    bool recovered = false;
    Type memberType;
    TypeDecl *member = nullptr;
    if (!memberTypes) {
      // If we're not allowed to complain or we couldn't fix the
      // source, bail out.
      if (!diagnoseErrors) {
        return ErrorType::get(TC.Context);
      }
  
      Type ty = diagnoseUnknownType(TC, DC, parentTy, parentRange, comp, options,
                                    resolver, unsatisfiedDependency);
      if (!ty || ty->is<ErrorType>()) {
        return ErrorType::get(TC.Context);
      }
  
      recovered = true;
      memberType = ty;
      member = cast_or_null<TypeDecl>(comp->getBoundDecl());
    } else {
      memberType = memberTypes.back().second;
      member = memberTypes.back().first;
    }
  
    if (parentTy->isExistentialType()) {
      if (diagnoseErrors)
        TC.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol,
                    comp->getIdentifier());
  
      return ErrorType::get(TC.Context);
    }
  
    // If there are generic arguments, apply them now.
    if (auto genComp = dyn_cast<GenericIdentTypeRepr>(comp))
      memberType = applyGenericTypeReprArgs(
        TC, memberType, comp->getIdLoc(), DC, genComp->getGenericArgs(),
        options.contains(TR_GenericSignature), resolver);
  
    if (member)
      comp->setValue(member);
    return memberType;
  }
  
  static Type resolveIdentTypeComponent(
                TypeChecker &TC, DeclContext *DC,
                ArrayRef<ComponentIdentTypeRepr *> components,
                TypeResolutionOptions options,
                bool diagnoseErrors,
                GenericTypeResolver *resolver,
                UnsatisfiedDependency *unsatisfiedDependency) {
    auto comp = components.back();
  
    // The first component uses unqualified lookup.
    auto parentComps = components.slice(0, components.size()-1);
    if (parentComps.empty()) {
      return resolveTopLevelIdentTypeComponent(TC, DC, comp, options,
                                               diagnoseErrors, resolver,
                                               unsatisfiedDependency);
    }
  
    // All remaining components use qualified lookup.
  
    // Resolve the parent type.
    Type parentTy = resolveIdentTypeComponent(TC, DC, parentComps, options,
                                              diagnoseErrors, resolver,
                                              unsatisfiedDependency);
    if (!parentTy || parentTy->is<ErrorType>()) return parentTy;
  
    // Resolve the nested type.
    SourceRange parentRange(parentComps.front()->getIdLoc(),
                            parentComps.back()->getSourceRange().End);
    return resolveNestedIdentTypeComponent(TC, DC, parentTy,
                                           parentRange, comp,
                                           options, diagnoseErrors,
                                           resolver,
                                           unsatisfiedDependency);
  }
  
  // FIXME: Merge this with diagAvailability in MiscDiagnostics.cpp.
  static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType,
                                        SourceLoc Loc, DeclContext *DC,
                                        TypeChecker &TC,
                                        bool AllowPotentiallyUnavailableProtocol) {
  
    if (auto CI = dyn_cast<ComponentIdentTypeRepr>(IdType)) {
      if (auto Attr = AvailableAttr::isUnavailable(TypeDecl)) {
        switch (Attr->getUnconditionalAvailability()) {
        case UnconditionalAvailabilityKind::None:
        case UnconditionalAvailabilityKind::Deprecated:
          break;
  
        case UnconditionalAvailabilityKind::Unavailable:
          if (!Attr->Rename.empty()) {
            TC.diagnose(Loc, diag::availability_decl_unavailable_rename,
                        CI->getIdentifier(), Attr->Rename)
              .fixItReplace(Loc, Attr->Rename);
          } else if (Attr->Message.empty()) {
            TC.diagnose(Loc, diag::availability_decl_unavailable,
                        CI->getIdentifier())
              .highlight(Loc);
          } else {
            EncodedDiagnosticMessage EncodedMessage(Attr->Message);
            TC.diagnose(Loc, diag::availability_decl_unavailable_msg,
                        CI->getIdentifier(), EncodedMessage.Message)
              .highlight(Loc);
          }
          break;
  
        case UnconditionalAvailabilityKind::UnavailableInSwift:
          if (Attr->Message.empty()) {
            TC.diagnose(Loc, diag::availability_decl_unavailable_in_swift,
                        CI->getIdentifier())
              .highlight(Loc);
          } else {
            EncodedDiagnosticMessage EncodedMessage(Attr->Message);
            TC.diagnose(Loc, diag::availability_decl_unavailable_in_swift_msg,
                        CI->getIdentifier(), EncodedMessage.Message)
              .highlight(Loc);
          }
          break;
        }
  
        auto DLoc = TypeDecl->getLoc();
        if (DLoc.isValid())
          TC.diagnose(DLoc, diag::availability_marked_unavailable,
                      CI->getIdentifier()).highlight(Attr->getRange());
        return true;
      }
  
      if (auto *Attr = TypeChecker::getDeprecated(TypeDecl)) {
        TC.diagnoseDeprecated(CI->getSourceRange(), DC, Attr,
                              CI->getIdentifier());
      }
  
      if (AllowPotentiallyUnavailableProtocol && isa<ProtocolDecl>(TypeDecl))
        return false;
  
      // Check for potential unavailability because of the minimum
      // deployment version.
      // We should probably unify this checking for deployment-version API
      // unavailability with checking for explicitly annotated unavailability.
      Optional<UnavailabilityReason> Unavail =
          TC.checkDeclarationAvailability(TypeDecl, Loc, DC);
      if (Unavail.hasValue()) {
        TC.diagnosePotentialUnavailability(TypeDecl, CI->getIdentifier(),
                                           CI->getSourceRange(), DC,
                                           Unavail.getValue());
      }
    }
  
    return false;
  }
  
  
  static bool diagnoseAvailability(Type ty, IdentTypeRepr *IdType, SourceLoc Loc,
                                   DeclContext *DC, TypeChecker &TC,
                                   bool AllowPotentiallyUnavailableProtocol) {
    if (auto *NAT = dyn_cast<NameAliasType>(ty.getPointer())) {
      if (checkTypeDeclAvailability(NAT->getDecl(), IdType, Loc, DC, TC,
                                    AllowPotentiallyUnavailableProtocol))
        return true;
    }
  
    // Look through substituted types to diagnose when the original
    // type is marked unavailable.
    if (auto *ST = dyn_cast<SubstitutedType>(ty.getPointer())) {
      if (diagnoseAvailability(ST->getOriginal(), IdType, Loc, DC, TC,
                               AllowPotentiallyUnavailableProtocol)) {
        return true;
      }
    }
  
    CanType canTy = ty.getCanonicalTypeOrNull();
    if (canTy.isNull())
      return false;
    if (auto NTD = canTy.getAnyNominal())
      return checkTypeDeclAvailability(NTD, IdType, Loc, DC, TC,
                                       AllowPotentiallyUnavailableProtocol);
  
    return false;
  }
  
  /// \brief Returns a valid type or ErrorType in case of an error.
  Type TypeChecker::resolveIdentifierType(
         DeclContext *DC,
         IdentTypeRepr *IdType,
         TypeResolutionOptions options,
         bool diagnoseErrors,
         GenericTypeResolver *resolver,
         UnsatisfiedDependency *unsatisfiedDependency) {
    assert(resolver && "Missing generic type resolver");
  
    auto ComponentRange = IdType->getComponentRange();
    auto Components = llvm::makeArrayRef(ComponentRange.begin(),
                                         ComponentRange.end());
    Type result = resolveIdentTypeComponent(*this, DC, Components, options, 
                                            diagnoseErrors, resolver,
                                            unsatisfiedDependency);
    if (!result) return nullptr;
  
    if (auto moduleTy = result->getAs<ModuleType>()) {
      if (diagnoseErrors) {
        auto moduleName = moduleTy->getModule()->getName();
        diagnose(Components.back()->getIdLoc(),
                 diag::use_undeclared_type, moduleName);
        diagnose(Components.back()->getIdLoc(),
                 diag::note_module_as_type, moduleName);
      }
      Components.back()->setInvalid();
      return ErrorType::get(Context);
    }
  
    // We allow a type to conform to a protocol that is less available than
    // the type itself. This enables a type to retroactively model or directly
    // conform to a protocl only available on newer OSes and yet still be used on
    // older OSes.
    // To support this, inside inheritance clauses we allow references to
    // protocols that are unavailable in the current type refinement context.
    bool AllowPotentiallyUnavailableProtocol =
        options.contains(TR_InheritanceClause);
  
    // Check the availability of the type. Skip checking for SIL.
    if (!(options & TR_SILType) && !(options & TR_AllowUnavailable) &&
        diagnoseAvailability(result, IdType,
                             Components.back()->getIdLoc(), DC, *this,
                             AllowPotentiallyUnavailableProtocol)) {
      Components.back()->setInvalid();
      return ErrorType::get(Context);
    }
    
    return result;
  }
  
  bool TypeChecker::validateType(TypeLoc &Loc, DeclContext *DC,
                                 TypeResolutionOptions options,
                                 GenericTypeResolver *resolver,
                                 UnsatisfiedDependency *unsatisfiedDependency) {
    // FIXME: Verify that these aren't circular and infinite size.
    
    // If we've already validated this type, don't do so again.
    if (Loc.wasValidated())
      return Loc.isError();
  
    if (Loc.getType().isNull()) {
      auto type = resolveType(Loc.getTypeRepr(), DC, options, resolver,
                              unsatisfiedDependency);
      if (!type) {
        // If a dependency went unsatisfied, just return false.
        if (unsatisfiedDependency) return false;
  
        type = ErrorType::get(Context);
      }
      Loc.setType(type, true);
      return Loc.isError();
    }
  
    Loc.setType(Loc.getType(), true);
    return Loc.isError();
  }
  
  namespace {
    const auto DefaultParameterConvention = ParameterConvention::Direct_Unowned;
    const auto DefaultResultConvention = ResultConvention::Unowned;
  
    class TypeResolver {
      TypeChecker &TC;
      ASTContext &Context;
      DeclContext *DC;
      GenericTypeResolver *Resolver;
      swift::UnsatisfiedDependency *UnsatisfiedDependency;
    public:
      TypeResolver(TypeChecker &tc, DeclContext *DC,
                   GenericTypeResolver *resolver,
                   swift::UnsatisfiedDependency *unsatisfiedDependency)
        : TC(tc), Context(tc.Context), DC(DC), Resolver(resolver),
          UnsatisfiedDependency(unsatisfiedDependency)
      {
        assert(resolver);
      }
  
      Type resolveType(TypeRepr *repr, TypeResolutionOptions options);
  
    private:
  
      Type resolveAttributedType(AttributedTypeRepr *repr,
                                 TypeResolutionOptions options);
      Type resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
                                 TypeResolutionOptions options);
      Type resolveASTFunctionType(FunctionTypeRepr *repr,
                                  TypeResolutionOptions options,
                                  FunctionType::ExtInfo extInfo
                                    = FunctionType::ExtInfo());
      Type resolveSILFunctionType(FunctionTypeRepr *repr,
                                  TypeResolutionOptions options,
                                  SILFunctionType::ExtInfo extInfo
                                    = SILFunctionType::ExtInfo(),
                                  ParameterConvention calleeConvention
                                    = DefaultParameterConvention);
      SILParameterInfo resolveSILParameter(TypeRepr *repr,
                                           TypeResolutionOptions options);
      bool resolveSILResults(TypeRepr *repr, TypeResolutionOptions options,
                             SmallVectorImpl<SILResultInfo> &results,
                             Optional<SILResultInfo> &errorResult);
      bool resolveSingleSILResult(TypeRepr *repr, TypeResolutionOptions options,
                                  SmallVectorImpl<SILResultInfo> &results,
                                  Optional<SILResultInfo> &errorResult);
      Type resolveInOutType(InOutTypeRepr *repr,
                            TypeResolutionOptions options);
      Type resolveArrayType(ArrayTypeRepr *repr,
                            TypeResolutionOptions options);
      Type resolveDictionaryType(DictionaryTypeRepr *repr,
                                 TypeResolutionOptions options);
      Type resolveOptionalType(OptionalTypeRepr *repr,
                               TypeResolutionOptions options);
      Type resolveImplicitlyUnwrappedOptionalType(ImplicitlyUnwrappedOptionalTypeRepr *repr,
                                        TypeResolutionOptions options);
      Type resolveTupleType(TupleTypeRepr *repr,
                            TypeResolutionOptions options);
      Type resolveProtocolCompositionType(ProtocolCompositionTypeRepr *repr,
                                          TypeResolutionOptions options);
      Type resolveMetatypeType(MetatypeTypeRepr *repr,
                               TypeResolutionOptions options);
      Type resolveProtocolType(ProtocolTypeRepr *repr,
                               TypeResolutionOptions options);
  
      Type buildMetatypeType(MetatypeTypeRepr *repr,
                             Type instanceType,
                             Optional<MetatypeRepresentation> storedRepr);
      Type buildProtocolType(ProtocolTypeRepr *repr,
                             Type instanceType,
                             Optional<MetatypeRepresentation> storedRepr);
    };
  }
  
  Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC,
                                TypeResolutionOptions options,
                                GenericTypeResolver *resolver,
                                UnsatisfiedDependency *unsatisfiedDependency) {
    PrettyStackTraceTypeRepr stackTrace(Context, "resolving", TyR);
  
    // Make sure we always have a resolver to use.
    PartialGenericTypeToArchetypeResolver defaultResolver(*this);
    if (!resolver)
      resolver = &defaultResolver;
  
    TypeResolver typeResolver(*this, DC, resolver, unsatisfiedDependency);
    return typeResolver.resolveType(TyR, options);
  }
  
  Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) {
    assert(repr && "Cannot validate null TypeReprs!");
  
    // If we know the type representation is invalid, just return an
    // error type.
    if (repr->isInvalid()) return ErrorType::get(TC.Context);
  
    // Strip the "is function input" bits unless this is a type that knows about
    // them.
    if (!isa<InOutTypeRepr>(repr) && !isa<TupleTypeRepr>(repr)) {
      options -= TR_ImmediateFunctionInput;
      options -= TR_FunctionInput;
    }
  
    switch (repr->getKind()) {
    case TypeReprKind::Error:
      return ErrorType::get(Context);
  
    case TypeReprKind::Attributed:
      return resolveAttributedType(cast<AttributedTypeRepr>(repr), options);
    case TypeReprKind::InOut:
      return resolveInOutType(cast<InOutTypeRepr>(repr), options);
  
    case TypeReprKind::SimpleIdent:
    case TypeReprKind::GenericIdent:
    case TypeReprKind::CompoundIdent:
      return TC.resolveIdentifierType(DC, cast<IdentTypeRepr>(repr), options,
                                      /*diagnoseErrors*/ true, Resolver,
                                      UnsatisfiedDependency);
  
    case TypeReprKind::Function:
      if (!(options & TR_SILType))
        return resolveASTFunctionType(cast<FunctionTypeRepr>(repr), options);
      return resolveSILFunctionType(cast<FunctionTypeRepr>(repr), options);
  
    case TypeReprKind::Array:
      return resolveArrayType(cast<ArrayTypeRepr>(repr), options);
  
    case TypeReprKind::Dictionary:
      return resolveDictionaryType(cast<DictionaryTypeRepr>(repr), options);
  
    case TypeReprKind::Optional:
      return resolveOptionalType(cast<OptionalTypeRepr>(repr), options);
  
    case TypeReprKind::ImplicitlyUnwrappedOptional:
      return resolveImplicitlyUnwrappedOptionalType(
               cast<ImplicitlyUnwrappedOptionalTypeRepr>(repr),
               options);
  
    case TypeReprKind::Tuple:
      return resolveTupleType(cast<TupleTypeRepr>(repr), options);
  
    case TypeReprKind::Named:
      llvm_unreachable("NamedTypeRepr only shows up as an element of Tuple");
  
    case TypeReprKind::ProtocolComposition:
      return resolveProtocolCompositionType(
               cast<ProtocolCompositionTypeRepr>(repr),
               options);
  
    case TypeReprKind::Metatype:
      return resolveMetatypeType(cast<MetatypeTypeRepr>(repr), options);
  
    case TypeReprKind::Protocol:
      return resolveProtocolType(cast<ProtocolTypeRepr>(repr), options);
  
    case TypeReprKind::Fixed:
      return cast<FixedTypeRepr>(repr)->getType();
    }
    llvm_unreachable("all cases should be handled");
  }
  
  Type TypeResolver::resolveAttributedType(AttributedTypeRepr *repr,
                                           TypeResolutionOptions options) {
    // Copy the attributes, since we're about to start hacking on them.
    TypeAttributes attrs = repr->getAttrs();
    assert(!attrs.empty());
  
    return resolveAttributedType(attrs, repr->getTypeRepr(), options);
  }
  
  Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
                                           TypeRepr *repr,
                                           TypeResolutionOptions options) {
    // The type we're working with, in case we want to build it differently
    // based on the attributes we see.
    Type ty;
    
    // In SIL *only*, allow @thin, @thick, or @objc_metatype to apply to
    // a metatype.
    if (attrs.has(TAK_thin) || attrs.has(TAK_thick) || 
        attrs.has(TAK_objc_metatype)) {
      if (auto SF = DC->getParentSourceFile()) {
        if (SF->Kind == SourceFileKind::SIL) {
          TypeRepr *base;
          if (auto metatypeRepr = dyn_cast<MetatypeTypeRepr>(repr)) {
            base = metatypeRepr->getBase();
          } else if (auto protocolRepr = dyn_cast<ProtocolTypeRepr>(repr)) {
            base = protocolRepr->getBase();
          } else {
            base = nullptr;
          }
  
          if (base) {
            Optional<MetatypeRepresentation> storedRepr;
            // The instance type is not a SIL type. We still want to allow
            // unavailable references, though.
            auto instanceOptions = options - TR_SILType | TR_AllowUnavailable;
            auto instanceTy = resolveType(base, instanceOptions);
            if (!instanceTy || instanceTy->is<ErrorType>())
              return instanceTy;
  
            // Check for @thin.
            if (attrs.has(TAK_thin)) {
              storedRepr = MetatypeRepresentation::Thin;
              attrs.clearAttribute(TAK_thin);
            }
  
            // Check for @thick.
            if (attrs.has(TAK_thick)) {
              if (storedRepr)
                TC.diagnose(repr->getStartLoc(), 
                            diag::sil_metatype_multiple_reprs);
                
              storedRepr = MetatypeRepresentation::Thick;
              attrs.clearAttribute(TAK_thick);
            }
  
            // Check for @objc_metatype.
            if (attrs.has(TAK_objc_metatype)) {
              if (storedRepr)
                TC.diagnose(repr->getStartLoc(), 
                            diag::sil_metatype_multiple_reprs);
                
              storedRepr = MetatypeRepresentation::ObjC;
              attrs.clearAttribute(TAK_objc_metatype);
            }
  
            if (instanceTy->is<ErrorType>()) {
              ty = instanceTy;
            } else if (auto metatype = dyn_cast<MetatypeTypeRepr>(repr)) {
              ty = buildMetatypeType(metatype, instanceTy, storedRepr);
            } else {
              ty = buildProtocolType(cast<ProtocolTypeRepr>(repr),
                                     instanceTy, storedRepr);
            }
          }
        }
      }
    }
  
    // Pass down the variable function type attributes to the
    // function-type creator.
    static const TypeAttrKind FunctionAttrs[] = {
      TAK_objc_block, TAK_convention, TAK_thin, TAK_noreturn,
      TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape
    };
  
    auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
      if (attrs.has(attr)) {
        TC.diagnose(attrs.getLoc(attr), diag::attribute_not_supported);
        attrs.clearAttribute(attr);
      }
    };
    
    // Some function representation attributes are not supported at source level;
    // only SIL knows how to handle them.  Reject them unless this is a SIL input.
    if (!(options & TR_SILType)) {
      for (auto silOnlyAttr : {TAK_callee_owned, TAK_callee_guaranteed}) {
        checkUnsupportedAttr(silOnlyAttr);
      }
    }  
  
    // Other function representation attributes are not normally supported at
    // source level, but we want to support them there in SIL files.
    auto SF = DC->getParentSourceFile();
    if (!SF || SF->Kind != SourceFileKind::SIL) {
      for (auto silOnlyAttr : {TAK_thin, TAK_thick}) {
        checkUnsupportedAttr(silOnlyAttr);
      }
    }
    
    bool hasFunctionAttr = false;
    for (auto i : FunctionAttrs)
      if (attrs.has(i)) {
        hasFunctionAttr = true;
        break;
      }
  
    // Function attributes require a syntactic function type.
    FunctionTypeRepr *fnRepr = dyn_cast<FunctionTypeRepr>(repr);
    if (hasFunctionAttr && fnRepr) {
  
      // Functions cannot be both @thin and @objc_block.
      bool thin = attrs.has(TAK_thin);
      bool block = attrs.has(TAK_objc_block);
      if (thin && block) {
        TC.diagnose(attrs.getLoc(TAK_objc_block),
                    diag::objc_block_cannot_be_thin)
          .highlight(attrs.getLoc(TAK_thin));
        thin = false;
      }
      
      bool isNoEscape = attrs.has(TAK_noescape);
  
      auto calleeConvention = ParameterConvention::Direct_Unowned;
      if (attrs.has(TAK_callee_owned)) {
        if (attrs.has(TAK_callee_guaranteed)) {
          TC.diagnose(attrs.getLoc(TAK_callee_owned),
                      diag::sil_function_repeat_convention, /*callee*/ 2);
        }
        calleeConvention = ParameterConvention::Direct_Owned;
      } else if (attrs.has(TAK_callee_guaranteed)) {
        calleeConvention = ParameterConvention::Direct_Guaranteed;
      }
  
      if (options & TR_SILType) {
        SILFunctionType::Representation rep;
  
        if (attrs.hasConvention()) {
          // SIL exposes a greater number of conventions than Swift source.
          auto parsedRep =
            llvm::StringSwitch<Optional<SILFunctionType::Representation>>
              (attrs.getConvention())
              .Case("thick", SILFunctionType::Representation::Thick)
              .Case("block", SILFunctionType::Representation::Block)
              .Case("thin", SILFunctionType::Representation::Thin)
              .Case("c", SILFunctionType::Representation::CFunctionPointer)
              .Case("method", SILFunctionType::Representation::Method)
              .Case("objc_method", SILFunctionType::Representation::ObjCMethod)
              .Case("witness_method", SILFunctionType::Representation::WitnessMethod)
              .Default(None);
          if (!parsedRep) {
            TC.diagnose(attrs.getLoc(TAK_convention),
                        diag::unsupported_sil_convention, attrs.getConvention());
            rep = SILFunctionType::Representation::Thin;
          } else {
            rep = *parsedRep;
          }
          
          // Don't allow both @convention and the old representation attrs.
          if (attrs.has(TAK_thin)) {
            TC.diagnose(attrs.getLoc(TAK_thin),
                        diag::convention_with_deprecated_representation_attribute,
                        "thin");
          }
          if (attrs.has(TAK_objc_block)) {
            TC.diagnose(attrs.getLoc(TAK_objc_block),
                        diag::convention_with_deprecated_representation_attribute,
                        "objc_block");
          }
        } else {
          // Error on the old @thin, @cc, and @objc_block attributes in SIL mode.
          if (thin) {
            TC.diagnose(attrs.getLoc(TAK_thin),
                        diag::sil_deprecated_convention_attribute,
                        "thin", "thin");
            rep = SILFunctionType::Representation::Block;
          } else if (block) {
            TC.diagnose(attrs.getLoc(TAK_thin),
                        diag::sil_deprecated_convention_attribute,
                        "objc_block", "block");
            rep = SILFunctionType::Representation::Block;
          } else {
            rep = SILFunctionType::Representation::Thick;
          }
        }
        
        // Resolve the function type directly with these attributes.
        SILFunctionType::ExtInfo extInfo(rep,
                                         attrs.has(TAK_noreturn));
        
        ty = resolveSILFunctionType(fnRepr, options, extInfo, calleeConvention);
        if (!ty || ty->is<ErrorType>()) return ty;
      } else {
        FunctionType::Representation rep;
        if (attrs.hasConvention()) {
          auto parsedRep =
            llvm::StringSwitch<Optional<FunctionType::Representation>>
              (attrs.getConvention())
              .Case("swift", FunctionType::Representation::Swift)
              .Case("block", FunctionType::Representation::Block)
              .Case("thin", FunctionType::Representation::Thin)
              .Case("c", FunctionType::Representation::CFunctionPointer)
              .Default(None);
          if (!parsedRep) {
            TC.diagnose(attrs.getLoc(TAK_convention),
                        diag::unsupported_convention, attrs.getConvention());
            rep = FunctionType::Representation::Swift;
          } else {
            rep = *parsedRep;
          }
          
          // Don't allow both @convention and the old representation attrs.
          if (attrs.has(TAK_thin)) {
            TC.diagnose(attrs.getLoc(TAK_thin),
                        diag::convention_with_deprecated_representation_attribute,
                        "thin");
          }
          if (attrs.has(TAK_objc_block)) {
            TC.diagnose(attrs.getLoc(TAK_objc_block),
                        diag::convention_with_deprecated_representation_attribute,
                        "objc_block");
          }
        } else {
          auto fixDeprecatedAttribute = [&](TypeAttrKind kind,
                                            StringRef oldName,
                                            StringRef newName) {
            auto start = attrs.getLoc(kind);
            
            SmallString<32> fixitString;
            {
              llvm::raw_svector_ostream os(fixitString);
              os << "convention(" << newName << ")";
            }
            
            TC.diagnose(start, diag::deprecated_convention_attribute,
                        oldName, newName)
              .highlight(start)
              .fixItReplace(start, fixitString);
          };
        
          // Handle the old attributes.
          if (thin) {
            rep = FunctionType::Representation::Thin;
            fixDeprecatedAttribute(TAK_thin, "thin", "thin");
          } else if (block) {
            rep = FunctionType::Representation::Block;
            fixDeprecatedAttribute(TAK_objc_block, "objc_block", "block");
          } else {
            rep = FunctionType::Representation::Swift;
          }
        }
        
        // Resolve the function type directly with these attributes.
        FunctionType::ExtInfo extInfo(rep,
                                      attrs.has(TAK_noreturn),
                                      /*autoclosure is a decl attr*/false,
                                      isNoEscape,
                                      fnRepr->throws());
  
        ty = resolveASTFunctionType(fnRepr, options, extInfo);
        if (!ty || ty->is<ErrorType>()) return ty;
      }
  
      for (auto i : FunctionAttrs)
        attrs.clearAttribute(i);
      attrs.convention = None;
    } else if (hasFunctionAttr) {
      for (auto i : FunctionAttrs) {
        if (attrs.has(i)) {
          TC.diagnose(attrs.getLoc(i), diag::attribute_requires_function_type);
          attrs.clearAttribute(i);
        }
      }
    } 
  
    // If we didn't build the type differently above, build it normally now.
    if (!ty) ty = resolveType(repr, options);
    if (!ty || ty->is<ErrorType>()) return ty;
  
    // In SIL, handle @opened (n), which creates an existential archetype.
    if (attrs.has(TAK_opened)) {
      if (!ty->isExistentialType()) {
        TC.diagnose(attrs.getLoc(TAK_opened), diag::opened_non_protocol, ty);
      } else {
        ty = ArchetypeType::getOpened(ty, attrs.OpenedID);
      }
      attrs.clearAttribute(TAK_opened);
    }
  
    // In SIL files *only*, permit @weak and @unowned to apply directly to types.
    if (attrs.hasOwnership()) {
      if (auto SF = DC->getParentSourceFile()) {
        if (SF->Kind == SourceFileKind::SIL) {
          if (((attrs.has(TAK_sil_weak) || attrs.has(TAK_sil_unmanaged)) &&
               ty->getAnyOptionalObjectType()) ||
              (!attrs.has(TAK_sil_weak) && ty->hasReferenceSemantics())) {
            ty = ReferenceStorageType::get(ty, attrs.getOwnership(), Context);
            attrs.clearOwnership();
          }
        }
      }
    }
    
    // In SIL *only*, allow @block_storage to specify a block storage type.
    if ((options & TR_SILType) && attrs.has(TAK_block_storage)) {
      ty = SILBlockStorageType::get(ty->getCanonicalType());
      attrs.clearAttribute(TAK_block_storage);
    }
    
    // In SIL *only*, allow @box to specify a box type.
    if ((options & TR_SILType) && attrs.has(TAK_box)) {
      ty = SILBoxType::get(ty->getCanonicalType());
      attrs.clearAttribute(TAK_box);
    }
    
    // Diagnose @local_storage in nested positions.
    if (attrs.has(TAK_local_storage)) {
      assert(DC->getParentSourceFile()->Kind == SourceFileKind::SIL);
      TC.diagnose(attrs.getLoc(TAK_local_storage),diag::sil_local_storage_nested);
      attrs.clearAttribute(TAK_local_storage);
    }
  
    for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i)
      if (attrs.has((TypeAttrKind)i))
        TC.diagnose(attrs.getLoc((TypeAttrKind)i),
                    diag::attribute_does_not_apply_to_type);
  
    return ty;
  }
  
  Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr,
                                            TypeResolutionOptions options,
                                            FunctionType::ExtInfo extInfo) {
    Type inputTy = resolveType(repr->getArgsTypeRepr(),
                               options | TR_ImmediateFunctionInput);
    if (!inputTy || inputTy->is<ErrorType>()) return inputTy;
  
    Type outputTy = resolveType(repr->getResultTypeRepr(),
                                options | TR_FunctionResult);
    if (!outputTy || outputTy->is<ErrorType>()) return outputTy;
  
    extInfo = extInfo.withThrows(repr->throws());
    
    // SIL uses polymorphic function types to resolve overloaded member functions.
    if (auto generics = repr->getGenericParams()) {
      return PolymorphicFunctionType::get(inputTy, outputTy, generics, extInfo);
    }
  
    auto fnTy = FunctionType::get(inputTy, outputTy, extInfo);
    // If the type is a block or C function pointer, it must be representable in
    // ObjC.
    switch (auto rep = extInfo.getRepresentation()) {
    case AnyFunctionType::Representation::Block:
    case AnyFunctionType::Representation::CFunctionPointer:
      if (!TC.isRepresentableInObjC(DC, fnTy)) {
        StringRef strName =
          rep == AnyFunctionType::Representation::Block ? "block" : "c";
        auto extInfo2 =
          extInfo.withRepresentation(AnyFunctionType::Representation::Swift);
        auto simpleFnTy = FunctionType::get(inputTy, outputTy, extInfo2);
        TC.diagnose(repr->getStartLoc(), diag::objc_convention_invalid,
                    simpleFnTy, strName);
      }
      break;
  
    case AnyFunctionType::Representation::Thin:
    case AnyFunctionType::Representation::Swift:
      break;
    }
    
    return fnTy;
  }
  
  Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
                                            TypeResolutionOptions options,
                                            SILFunctionType::ExtInfo extInfo,
                                            ParameterConvention callee) {
    bool hasError = false;
  
    SmallVector<SILParameterInfo, 4> params;
    if (auto tuple = dyn_cast<TupleTypeRepr>(repr->getArgsTypeRepr())) {
      // SIL functions cannot be variadic.
      if (tuple->hasEllipsis()) {
        TC.diagnose(tuple->getEllipsisLoc(), diag::sil_function_ellipsis);
      }
  
      for (auto elt : tuple->getElements()) {
        if (auto named = dyn_cast<NamedTypeRepr>(elt)) {
          TC.diagnose(named->getNameLoc(), diag::sil_function_label);
          elt = named->getTypeRepr();
        }
  
        auto param = resolveSILParameter(elt,options | TR_ImmediateFunctionInput);
        params.push_back(param);
        if (!param.getType()) return nullptr;
  
        if (param.getType()->is<ErrorType>())
          hasError = true;
      }
    } else {
      SILParameterInfo param = resolveSILParameter(repr->getArgsTypeRepr(),
                                             options | TR_ImmediateFunctionInput);
      params.push_back(param);
      if (!param.getType()) return nullptr;
  
      if (param.getType()->is<ErrorType>())
        hasError = true;
    }
  
    SILResultInfo result;
    Optional<SILResultInfo> errorResult;
    {
      // For now, resolveSILResults only returns a single ordinary result.
      // FIXME: Deal with unsatisfied dependencies.
      SmallVector<SILResultInfo, 1> ordinaryResults;
      if (resolveSILResults(repr->getResultTypeRepr(),
                            options | TR_FunctionResult,
                            ordinaryResults, errorResult)) {
        hasError = true;
      } else {
        if (ordinaryResults.empty()) {
          result = SILResultInfo(TupleType::getEmpty(TC.Context),
                                 ResultConvention::Unowned);
        } else {
          result = ordinaryResults.front();
        }
      }
    }
  
    if (hasError) {
      return ErrorType::get(Context);
    }
  
    // FIXME: Remap the parsed context types to interface types.
    GenericSignature *genericSig = nullptr;
    SmallVector<SILParameterInfo, 4> interfaceParams;
    SILResultInfo interfaceResult;
    Optional<SILResultInfo> interfaceErrorResult;
    if (repr->getGenericParams()) {
      llvm::DenseMap<ArchetypeType*, Type> archetypeMap;
      genericSig
        = repr->getGenericParams()->getAsCanonicalGenericSignature(archetypeMap,
                                                                   Context);
      
      auto getArchetypesAsDependentTypes = [&](Type t) -> Type {
        if (!t) return t;
        if (auto arch = t->getAs<ArchetypeType>()) {
          // As a kludge, we allow Self archetypes of protocol_methods to be
          // unapplied.
          if (arch->getSelfProtocol() && !archetypeMap.count(arch))
            return arch;
          return arch->getAsDependentType(archetypeMap);
        }
        return t;
      };
      
      for (auto &param : params) {
        auto transParamType =
          param.getType().transform(getArchetypesAsDependentTypes)
            ->getCanonicalType();
        interfaceParams.push_back(param.getWithType(transParamType));
      }
      auto transResultType =
        result.getType().transform(getArchetypesAsDependentTypes)
          ->getCanonicalType();
      interfaceResult = result.getWithType(transResultType);
  
      if (errorResult) {
        auto transErrorResultType =
          errorResult->getType().transform(getArchetypesAsDependentTypes)
            ->getCanonicalType();
        interfaceErrorResult =
          errorResult->getWithType(transErrorResultType);
      }
    } else {
      interfaceParams = params;
      interfaceResult = result;
      interfaceErrorResult = errorResult;
    }
    return SILFunctionType::get(genericSig, extInfo,
                                callee,
                                interfaceParams, interfaceResult,
                                interfaceErrorResult,
                                Context);
  }
  
  SILParameterInfo TypeResolver::resolveSILParameter(
                                   TypeRepr *repr,
                                   TypeResolutionOptions options) {
    assert((options & TR_FunctionInput) | (options & TR_ImmediateFunctionInput) &&
           "Parameters should be marked as inputs");
    auto convention = DefaultParameterConvention;
    Type type;
    bool hadError = false;
  
    if (auto attrRepr = dyn_cast<AttributedTypeRepr>(repr)) {
      auto attrs = attrRepr->getAttrs();
      auto checkFor = [&](TypeAttrKind tak, ParameterConvention attrConv) {
        if (!attrs.has(tak)) return;
        if (convention != DefaultParameterConvention) {
          TC.diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention,
                      /*input*/ 0);
          hadError = true;
        }
        attrs.clearAttribute(tak);
        convention = attrConv;
      };
      checkFor(TypeAttrKind::TAK_in_guaranteed,
               ParameterConvention::Indirect_In_Guaranteed);
      checkFor(TypeAttrKind::TAK_in, ParameterConvention::Indirect_In);
      checkFor(TypeAttrKind::TAK_out, ParameterConvention::Indirect_Out);
      checkFor(TypeAttrKind::TAK_inout, ParameterConvention::Indirect_Inout);
      checkFor(TypeAttrKind::TAK_inout_aliasable,
               ParameterConvention::Indirect_InoutAliasable);
      checkFor(TypeAttrKind::TAK_owned, ParameterConvention::Direct_Owned);
      checkFor(TypeAttrKind::TAK_guaranteed,
               ParameterConvention::Direct_Guaranteed);
      checkFor(TypeAttrKind::TAK_deallocating,
               ParameterConvention::Direct_Deallocating);
  
      type = resolveAttributedType(attrs, attrRepr->getTypeRepr(), options);
    } else {
      type = resolveType(repr, options);
    }
  
    if (!type) return SILParameterInfo(CanType(), convention);
    if (hadError) type = ErrorType::get(Context);
    return SILParameterInfo(type->getCanonicalType(), convention);
  }
  
  bool TypeResolver::resolveSingleSILResult(TypeRepr *repr,
                                            TypeResolutionOptions options,
                                SmallVectorImpl<SILResultInfo> &ordinaryResults,
                                         Optional<SILResultInfo> &errorResult) {
    Type type;
    auto convention = DefaultResultConvention;
    bool isErrorResult = false;
  
    if (auto attrRepr = dyn_cast<AttributedTypeRepr>(repr)) {
      // Copy the attributes out; we're going to destructively modify them.
      auto attrs = attrRepr->getAttrs();
  
      // Recognize @error.
      if (attrs.has(TypeAttrKind::TAK_error)) {
        attrs.clearAttribute(TypeAttrKind::TAK_error);
        isErrorResult = true;
  
        // Error results are always implicitly @owned.
        convention = ResultConvention::Owned;
      }
  
      // Recognize result conventions.
      bool hadError = false;
      auto checkFor = [&](TypeAttrKind tak, ResultConvention attrConv) {
        if (!attrs.has(tak)) return;
        if (convention != DefaultResultConvention) {
          TC.diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention,
                      /*result*/ 1);
          hadError = true;
        }
        attrs.clearAttribute(tak);
        convention = attrConv;
      };
      checkFor(TypeAttrKind::TAK_owned, ResultConvention::Owned);
      checkFor(TypeAttrKind::TAK_unowned_inner_pointer,
               ResultConvention::UnownedInnerPointer);
      checkFor(TypeAttrKind::TAK_autoreleased, ResultConvention::Autoreleased);
      if (hadError) return true;
  
      type = resolveAttributedType(attrs, attrRepr->getTypeRepr(), options);
    } else {
      type = resolveType(repr, options);
    }
  
    // Propagate type-resolution errors out.
    if (!type || type->is<ErrorType>()) return true;
  
    assert(!isErrorResult || convention == ResultConvention::Owned);
    SILResultInfo resolvedResult(type->getCanonicalType(), convention);
  
    // TODO: we want to generalize this to allow multiple normal results.
    // But for now, just allow one.
    if (!isErrorResult) {
      if (!ordinaryResults.empty()) {
        TC.diagnose(repr->getStartLoc(), diag::sil_function_multiple_results);
        return true;
      }
  
      ordinaryResults.push_back(resolvedResult);
      return false;
    }
  
    // Error result types must have pointer-like representation.
    // FIXME: check that here?
  
    // We don't expect to have a reason to support multiple independent
    // error results.  (Would this be disjunctive or conjunctive?)
    if (errorResult.hasValue()) {
      TC.diagnose(repr->getStartLoc(),
                  diag::sil_function_multiple_error_results);
      return true;
    }
  
    errorResult = resolvedResult;
    return false;
  }
  
  static bool hasElementWithSILResultAttribute(TupleTypeRepr *tuple) {
    for (auto elt : tuple->getElements()) {
      if (auto attrRepr = dyn_cast<AttributedTypeRepr>(elt)) {
        const TypeAttributes &attrs = attrRepr->getAttrs();
        if (attrs.has(TypeAttrKind::TAK_owned) ||
            attrs.has(TypeAttrKind::TAK_unowned_inner_pointer) ||
            attrs.has(TypeAttrKind::TAK_autoreleased) ||
            attrs.has(TypeAttrKind::TAK_error)) {
          return true;
        }
      }
    }
    return false;
  }
  
  bool TypeResolver::resolveSILResults(TypeRepr *repr,
                                       TypeResolutionOptions options,
                                  SmallVectorImpl<SILResultInfo> &ordinaryResults,
                                  Optional<SILResultInfo> &errorResult) {
    assert(options & TR_FunctionResult && "Should be marked as a result");
  
    // When we generalize SIL to handle multiple normal results, we
    // should always split up a tuple (a single level deep only).  Until
    // then, we need to recognize when the tuple elements don't use any
    // SIL result attributes and keep it as a single result.
    if (auto tuple = dyn_cast<TupleTypeRepr>(repr)) {
      if (hasElementWithSILResultAttribute(tuple)) {
        bool hadError = false;
        for (auto elt : tuple->getElements()) {
          if (resolveSingleSILResult(elt, options, ordinaryResults, errorResult))
            hadError = true;
        }
        return hadError;
      }
    }
  
    return resolveSingleSILResult(repr, options, ordinaryResults, errorResult);
  }
  
  Type TypeResolver::resolveInOutType(InOutTypeRepr *repr,
                                      TypeResolutionOptions options) {
    Type ty = resolveType(cast<InOutTypeRepr>(repr)->getBase(), options);
    if (!ty || ty->is<ErrorType>()) return ty;
  
    if (!(options & TR_FunctionInput) &&
        !(options & TR_ImmediateFunctionInput)) {
      TC.diagnose(repr->getInOutLoc(), diag::inout_only_parameter);
      return ErrorType::get(Context);
    }
    
    return InOutType::get(ty);
  }
  
  
  Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr,
                                      TypeResolutionOptions options) {
    // FIXME: diagnose non-materializability of element type!
    Type baseTy = resolveType(repr->getBase(), withoutContext(options));
    if (!baseTy || baseTy->is<ErrorType>()) return baseTy;
    
    if (ExprHandle *sizeEx = repr->getSize()) {
      // FIXME: We don't support fixed-length arrays yet.
      // FIXME: We need to check Size! (It also has to be convertible to int).
      TC.diagnose(repr->getBrackets().Start, diag::unsupported_fixed_length_array)
        .highlight(sizeEx->getExpr()->getSourceRange());
      return ErrorType::get(Context);
    }
  
    auto sliceTy = TC.getArraySliceType(repr->getBrackets().Start, baseTy);
    if (!sliceTy)
      return ErrorType::get(Context);
  
    return sliceTy;
  }
  
  Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr,
                                           TypeResolutionOptions options) {
    // FIXME: diagnose non-materializability of key/value type?
    Type keyTy = resolveType(repr->getKey(), withoutContext(options));
    if (!keyTy || keyTy->is<ErrorType>()) return keyTy;
  
    Type valueTy = resolveType(repr->getValue(), withoutContext(options));
    if (!valueTy || valueTy->is<ErrorType>()) return valueTy;
    
    if (auto dictTy = TC.getDictionaryType(repr->getBrackets().Start, keyTy, 
                                           valueTy)) {
      // Check the requirements on the generic arguments.
      auto unboundTy = UnboundGenericType::get(TC.Context.getDictionaryDecl(),
                                               nullptr, TC.Context);
      TypeLoc args[2] = { TypeLoc(repr->getKey()), TypeLoc(repr->getValue()) };
  
      if (!TC.applyGenericArguments(unboundTy, repr->getStartLoc(), DC, args,
                                    options.contains(TR_GenericSignature),
                                    Resolver)) {
        return ErrorType::get(TC.Context);
      }
  
      return dictTy;
    }
  
    return ErrorType::get(Context);
  }
  
  Type TypeResolver::resolveOptionalType(OptionalTypeRepr *repr,
                                         TypeResolutionOptions options) {
    // The T in T? is a generic type argument and therefore always an AST type.
    // FIXME: diagnose non-materializability of element type!
    Type baseTy = resolveType(repr->getBase(), withoutContext(options));
    if (!baseTy || baseTy->is<ErrorType>()) return baseTy;
  
    auto optionalTy = TC.getOptionalType(repr->getQuestionLoc(), baseTy);
    if (!optionalTy) return ErrorType::get(Context);
  
    return optionalTy;
  }
  
  Type TypeResolver::resolveImplicitlyUnwrappedOptionalType(
         ImplicitlyUnwrappedOptionalTypeRepr *repr,
         TypeResolutionOptions options) {
    // The T in T! is a generic type argument and therefore always an AST type.
    // FIXME: diagnose non-materializability of element type!
    Type baseTy = resolveType(repr->getBase(), withoutContext(options));
    if (!baseTy || baseTy->is<ErrorType>()) return baseTy;
  
    auto uncheckedOptionalTy =
      TC.getImplicitlyUnwrappedOptionalType(repr->getExclamationLoc(), baseTy);
    if (!uncheckedOptionalTy)
      return ErrorType::get(Context);
  
    return uncheckedOptionalTy;
  }
  
  Type TypeResolver::resolveTupleType(TupleTypeRepr *repr,
                                      TypeResolutionOptions options) {
    SmallVector<TupleTypeElt, 8> elements;
    elements.reserve(repr->getElements().size());
    
    // If this is the top level of a function input list, peel off the
    // ImmediateFunctionInput marker and install a FunctionInput one instead.
    auto elementOptions = withoutContext(options);
    if (options & TR_ImmediateFunctionInput)
      elementOptions |= TR_FunctionInput;
    
    for (auto tyR : repr->getElements()) {
      if (NamedTypeRepr *namedTyR = dyn_cast<NamedTypeRepr>(tyR)) {
        Type ty = resolveType(namedTyR->getTypeRepr(), elementOptions);
        if (!ty || ty->is<ErrorType>()) return ty;
  
        elements.push_back(TupleTypeElt(ty, namedTyR->getName()));
      } else {
        Type ty = resolveType(tyR, elementOptions);
        if (!ty || ty->is<ErrorType>()) return ty;
  
        elements.push_back(TupleTypeElt(ty));
      }
    }
  
    // Tuple representations are limited outside of function inputs.
    if (!(options & TR_ImmediateFunctionInput)) {
      bool complained = false;
  
      // Variadic tuples are not permitted.
      if (repr->hasEllipsis()) {
        TC.diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis);
        repr->removeEllipsis();
        complained = true;
      } 
  
      // Single-element labeled tuples are not permitted, either.
      if (elements.size() == 1 && elements[0].hasName() &&
          !(options & TR_EnumCase)) {
        if (!complained) {
          auto named = cast<NamedTypeRepr>(repr->getElement(0));
          TC.diagnose(repr->getElement(0)->getStartLoc(),
                      diag::tuple_single_element)
            .fixItRemoveChars(named->getStartLoc(),
                              named->getTypeRepr()->getStartLoc());
        }
  
        elements[0] = TupleTypeElt(elements[0].getType());
      }
    }
  
    if (repr->hasEllipsis()) {
      auto &element = elements[repr->getEllipsisIndex()];
      Type baseTy = element.getType();
      Type fullTy = TC.getArraySliceType(repr->getEllipsisLoc(), baseTy);
      Identifier name = element.getName();
      element = TupleTypeElt(fullTy, name, DefaultArgumentKind::None, true);
    }
  
    return TupleType::get(elements, Context);
  }
  
  Type TypeResolver::resolveProtocolCompositionType(
                                           ProtocolCompositionTypeRepr *repr,
                                           TypeResolutionOptions options) {
    SmallVector<Type, 4> ProtocolTypes;
    for (auto tyR : repr->getProtocols()) {
      Type ty = TC.resolveType(tyR, DC, withoutContext(options), Resolver);
      if (!ty || ty->is<ErrorType>()) return ty;
  
      if (!ty->isExistentialType()) {
        TC.diagnose(tyR->getStartLoc(), diag::protocol_composition_not_protocol,
                    ty);
        continue;
      }
  
      ProtocolTypes.push_back(ty);
    }
    return ProtocolCompositionType::get(Context, ProtocolTypes);
  }
  
  Type TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr,
                                         TypeResolutionOptions options) {
    // The instance type of a metatype is always abstract, not SIL-lowered.
    Type ty = resolveType(repr->getBase(), withoutContext(options));
    if (!ty || ty->is<ErrorType>()) return ty;
  
    Optional<MetatypeRepresentation> storedRepr;
    
    // In SIL mode, a metatype must have a @thin, @thick, or
    // @objc_metatype attribute, so metatypes should have been lowered
    // in resolveAttributedType.
    if (options & TR_SILType) {
      TC.diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr);
      storedRepr = MetatypeRepresentation::Thick;
    }
  
    return buildMetatypeType(repr, ty, storedRepr);
  }
  
  Type TypeResolver::buildMetatypeType(
         MetatypeTypeRepr *repr,
         Type instanceType,
         Optional<MetatypeRepresentation> storedRepr) {
    if (instanceType->isAnyExistentialType()) {
      // TODO: diagnose invalid representations?
      return ExistentialMetatypeType::get(instanceType, storedRepr);
    } else {
      return MetatypeType::get(instanceType, storedRepr);
    }
  }
  
  Type TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr,
                                         TypeResolutionOptions options) {
    // The instance type of a metatype is always abstract, not SIL-lowered.
    Type ty = resolveType(repr->getBase(), withoutContext(options));
    if (!ty || ty->is<ErrorType>()) return ty;
  
    Optional<MetatypeRepresentation> storedRepr;
    
    // In SIL mode, a metatype must have a @thin, @thick, or
    // @objc_metatype attribute, so metatypes should have been lowered
    // in resolveAttributedType.
    if (options & TR_SILType) {
      TC.diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr);
      storedRepr = MetatypeRepresentation::Thick;
    }
  
    return buildProtocolType(repr, ty, storedRepr);
  }
  
  Type TypeResolver::buildProtocolType(
         ProtocolTypeRepr *repr,
         Type instanceType,
         Optional<MetatypeRepresentation> storedRepr) {
    if (!instanceType->isAnyExistentialType()) {
      TC.diagnose(repr->getProtocolLoc(), diag::dot_protocol_on_non_existential,
                  instanceType);
      return ErrorType::get(TC.Context);
    }
  
    return MetatypeType::get(instanceType, storedRepr);
  }
  
  Type TypeChecker::substMemberTypeWithBase(Module *module,
                                            const ValueDecl *member,
                                            Type baseTy, bool isTypeReference) {
    Type memberType = isTypeReference
                        ? cast<TypeDecl>(member)->getDeclaredInterfaceType()
                        : member->getInterfaceType();
  
    if (isTypeReference) {
      // The declared interface type for a generic type will have the type
      // arguments; strip them off.
      if (auto nominalTypeDecl = dyn_cast<NominalTypeDecl>(member)) {
        if (auto boundGenericTy = memberType->getAs<BoundGenericType>()) {
          memberType = UnboundGenericType::get(
                         const_cast<NominalTypeDecl *>(nominalTypeDecl),
                         boundGenericTy->getParent(),
                         Context);
        }
      }
    }
  
    return baseTy->getTypeOfMember(module, member, this, memberType);
  }
  
  Type TypeChecker::getSuperClassOf(Type type) {
    return type->getSuperclass(this);
  }
  
  Type TypeChecker::resolveMemberType(DeclContext *dc, Type type,
                                      Identifier name) {
    LookupTypeResult memberTypes = lookupMemberType(dc, type, name);
    if (!memberTypes)
      return Type();
  
    // FIXME: Detect ambiguities here?
    return memberTypes.back().second;
  }
  
  /// Look up and validate a type declared in the standard library.
  static CanType lookupUniqueTypeInLibrary(TypeChecker &TC,
                                           Module *stdlib,
                                           Identifier name) {
    SmallVector<ValueDecl *, 4> results;
    stdlib->lookupValue({}, name, NLKind::UnqualifiedLookup, results);
  
    TypeDecl *type = nullptr;
    for (auto result: results) {
      if (auto foundType = dyn_cast<TypeDecl>(result)) {
        // Fail if we find two types with this name.
        if (type) return CanType();
        type = foundType;
      }
    }
  
    // Fail if we didn't find a type.
    if (!type) return CanType();
  
    TC.validateDecl(type);
    if (type->isInvalid()) return CanType();
  
    return type->getDeclaredType()->getCanonicalType();
  }
  
  static void lookupAndAddLibraryTypes(TypeChecker &TC,
                                       Module *Stdlib,
                                       ArrayRef<Identifier> TypeNames,
                                       llvm::DenseSet<CanType> &Types) {
    SmallVector<ValueDecl *, 4> Results;
    for (Identifier Id : TypeNames) {
      Stdlib->lookupValue({}, Id, NLKind::UnqualifiedLookup, Results);
      for (auto *VD : Results) {
        if (auto *TD = dyn_cast<TypeDecl>(VD)) {
          TC.validateDecl(TD);
          Types.insert(TD->getDeclaredType()->getCanonicalType());
        }
      }
      Results.clear();
    }
  }
  
  /// Emit an additional diagnostic describing why we are applying @objc to the
  /// decl, if this is not obvious from the decl itself.
  static void describeObjCReason(TypeChecker &TC, const ValueDecl *VD,
                                 ObjCReason Reason) {
    if (Reason == ObjCReason::MemberOfObjCProtocol) {
      TC.diagnose(VD->getLoc(), diag::objc_inferring_on_objc_protocol_member);
    } else if (Reason == ObjCReason::OverridesObjC) {
      unsigned kind = isa<VarDecl>(VD) ? 0
                    : isa<SubscriptDecl>(VD) ? 1
                    : isa<ConstructorDecl>(VD) ? 2
                    : 3;
  
      auto overridden = VD->getOverriddenDecl();
      if (overridden->getLoc().isValid()) {
        TC.diagnose(overridden->getLoc(), diag::objc_overriding_objc_decl,
                    kind, VD->getOverriddenDecl()->getFullName());
      }
    }
  }
  
  static Type getFunctionParamType(const Pattern *P) {
    if (auto *TP = dyn_cast<TypedPattern>(P))
      return TP->getType();
    return {};
  }
  
  static SourceRange getFunctionParamTypeSourceRange(const Pattern *P) {
    if (auto *TP = dyn_cast<TypedPattern>(P))
      return TP->getTypeLoc().getTypeRepr()->getSourceRange();
    return {};
  }
  
  static bool isParamRepresentableInObjC(TypeChecker &TC,
                                         const DeclContext *DC,
                                         const Pattern *P) {
    // Look through 'var' pattern.
    if (auto VP = dyn_cast<VarPattern>(P))
      P = VP->getSubPattern();
  
    auto *TP = dyn_cast<TypedPattern>(P);
    if (!TP)
      return false;
    if (!TC.isRepresentableInObjC(DC, TP->getType()))
      return false;
    auto *SubPattern = TP->getSubPattern();
    return isa<NamedPattern>(SubPattern) || isa<AnyPattern>(SubPattern);
  }
  
  static void diagnoseFunctionParamNotRepresentable(
      TypeChecker &TC, const AbstractFunctionDecl *AFD, unsigned NumParams,
      unsigned ParamIndex, const Pattern *P, ObjCReason Reason) {
    if (Reason == ObjCReason::DoNotDiagnose)
      return;
  
    if (NumParams == 1) {
      TC.diagnose(AFD->getLoc(), diag::objc_invalid_on_func_single_param_type,
                  getObjCDiagnosticAttrKind(Reason));
    } else {
      TC.diagnose(AFD->getLoc(), diag::objc_invalid_on_func_param_type,
                  ParamIndex + 1, getObjCDiagnosticAttrKind(Reason));
    }
    if (Type ParamTy = getFunctionParamType(P)) {
      SourceRange SR = getFunctionParamTypeSourceRange(P);
      TC.diagnoseTypeNotRepresentableInObjC(AFD, ParamTy, SR);
    }
    describeObjCReason(TC, AFD, Reason);
  }
  
  static bool isParamPatternRepresentableInObjC(TypeChecker &TC,
                                                const AbstractFunctionDecl *AFD,
                                                const Pattern *P,
                                                ObjCReason Reason) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
    if (auto *TP = dyn_cast<TuplePattern>(P)) {
      auto Fields = TP->getElements();
      unsigned NumParams = Fields.size();
  
      // Varargs are not representable in Objective-C.
      if (TP->hasAnyEllipsis()) {
        if (Diagnose && Reason != ObjCReason::DoNotDiagnose) {
          TC.diagnose(TP->getAnyEllipsisLoc(),
                      diag::objc_invalid_on_func_variadic,
                      getObjCDiagnosticAttrKind(Reason));
          describeObjCReason(TC, AFD, Reason);
        }
  
        return false;
      }
  
      if (NumParams == 0)
        return true;
  
      bool IsObjC = true;
      for (unsigned ParamIndex = 0; ParamIndex != NumParams; ParamIndex++) {
        auto &TupleElt = Fields[ParamIndex];
        if (!isParamRepresentableInObjC(TC, AFD, TupleElt.getPattern())) {
          // Permit '()' when this method overrides a method with a
          // foreign error convention that replaces NSErrorPointer with ()
          // and this is the replaced parameter.
          AbstractFunctionDecl *overridden;
          if (TupleElt.getPattern()->getType()->isVoid() &&
              AFD->isBodyThrowing() &&
              (overridden = AFD->getOverriddenDecl())) {
            auto foreignError = overridden->getForeignErrorConvention();
            if (foreignError &&
                foreignError->isErrorParameterReplacedWithVoid() &&
                foreignError->getErrorParameterIndex() == ParamIndex) {
              continue;
            }
          }
  
          IsObjC = false;
          if (!Diagnose) {
            // Save some work and return as soon as possible if we are not
            // producing diagnostics.
            return IsObjC;
          }
          diagnoseFunctionParamNotRepresentable(TC, AFD, NumParams, ParamIndex,
                                                TupleElt.getPattern(), Reason);
        }
      }
      return IsObjC;
    }
    auto *PP = cast<ParenPattern>(P);
    if (!isParamRepresentableInObjC(TC, AFD, PP->getSubPattern())) {
      diagnoseFunctionParamNotRepresentable(TC, AFD, 1, 1, PP->getSubPattern(),
                                            Reason);
      return false;
    }
    return true;
  }
  
  /// Check whether the given declaration occurs within a constrained
  /// extension, or an extension of a class with generic ancestry, and
  /// therefore is not representable in Objective-C.
  static bool checkObjCInExtensionContext(TypeChecker &tc,
                                          const ValueDecl *value,
                                          bool diagnose) {
    auto DC = value->getDeclContext();
  
    if (auto ED = dyn_cast<ExtensionDecl>(DC)) {
      if (ED->getTrailingWhereClause()) {
        if (diagnose) {
          tc.diagnose(value->getLoc(), diag::objc_in_extension_context);
        }
        return true;
      }
  
      // Check if any classes in the inheritance hierarchy have generic
      // parameters.
      // FIXME: This is a current limitation, not inherent. We don't have
      // a concrete class to attach Objective-C category metadata to.
      Type extendedTy = ED->getDeclaredTypeInContext();
      while (!extendedTy.isNull()) {
        const ClassDecl *CD = extendedTy->getClassOrBoundGenericClass();
        if (!CD)
          break;
  
        if (CD->getGenericParams()) {
          if (diagnose) {
            tc.diagnose(value->getLoc(), diag::objc_in_generic_extension);
          }
          return true;
        }
  
        extendedTy = CD->getSuperclass();
      }
    }
  
    return false;
  }
  
  /// Check whether the given declaration contains its own generic parameters,
  /// and therefore is not representable in Objective-C.
  static bool checkObjCWithGenericParams(TypeChecker &TC,
                                         const AbstractFunctionDecl *AFD,
                                         ObjCReason Reason) {
    bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
  
    if (AFD->getGenericParams()) {
      // Diagnose this problem, if asked to.
      if (Diagnose) {
        TC.diagnose(AFD->getLoc(), diag::objc_invalid_with_generic_params,
                    getObjCDiagnosticAttrKind(Reason));
        describeObjCReason(TC, AFD, Reason);
      }
  
      return true;
    }
  
    return false;
  }
  
  static bool isForeignClassContext(DeclContext *DC) {
    auto type = DC->getDeclaredTypeInContext();
    if (!type)
      return false;
    auto clas = type->getClassOrBoundGenericClass();
    if (!clas)
      return false;
    return clas->isForeign();
  }
  
  /// CF types cannot have @objc methods, because they don't have real class
  /// objects.
  static bool checkObjCInForeignClassContext(TypeChecker &TC,
                                             const ValueDecl *VD,
                                             ObjCReason Reason) {
    bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
  
    if (isForeignClassContext(VD->getDeclContext())) {
      if (Diagnose) {
        TC.diagnose(VD->getLoc(), diag::objc_invalid_on_foreign_class,
                    getObjCDiagnosticAttrKind(Reason));
        describeObjCReason(TC, VD, Reason);
      }
      return true;
    }
  
    return false;
  }
  
  bool TypeChecker::isCIntegerType(const DeclContext *DC, Type T) {
    if (CIntegerTypes.empty())
      fillObjCRepresentableTypeCache(DC);
    return CIntegerTypes.count(T->getCanonicalType());
  }
  
  /// Determines whether the given type is bridged to an Objective-C class type.
  static bool isBridgedToObjectiveCClass(DeclContext *dc, Type type) {
    // Simple case: bridgeable object types.
    if (type->isBridgeableObjectType())
      return true;
  
    // Determine whether this type is bridged to Objective-C.
    ASTContext &ctx = type->getASTContext();
    Optional<Type> bridged = ctx.getBridgedToObjC(dc, type,
                                                  ctx.getLazyResolver());
    if (!bridged)
      return false;
  
    // Check whether we're bridging to a class.
    auto classDecl = (*bridged)->getClassOrBoundGenericClass();
    if (!classDecl)
      return false;
  
    // Allow anything that isn't bridged to NSNumber.
    // FIXME: This feels like a hack, but we don't have the right predicate
    // anywhere.
    return classDecl->getName().str() != "NSNumber";
  }
  
  /// Determine whether this is a trailing closure type.
  static AnyFunctionType *isTrailingClosure(Type type) {
    // Only consider the rvalue type.
    type = type->getRValueType();
  
    // Look through one level of optionality.
    if (auto objectType = type->getAnyOptionalObjectType())
      type = objectType;
  
    // Is it a function type?
    return type->getAs<AnyFunctionType>();
  }
  
  bool TypeChecker::isRepresentableInObjC(
         const AbstractFunctionDecl *AFD,
         ObjCReason Reason,
         Optional<ForeignErrorConvention> &errorConvention) {
    // Clear out the error convention. It will be added later if needed.
    errorConvention = None;
  
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
  
    if (checkObjCInForeignClassContext(*this, AFD, Reason))
      return false;
    if (checkObjCWithGenericParams(*this, AFD, Reason))
      return false;
    if (checkObjCInExtensionContext(*this, AFD, Diagnose))
      return false;
  
    if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
      if (FD->isAccessor()) {
        // Accessors can only be @objc if the storage declaration is.
        auto storage = FD->getAccessorStorageDecl();
        validateDecl(storage);
        if (!storage->isObjC()) {
          if (Diagnose) {
            auto error = FD->isGetter()
                      ? (isa<VarDecl>(storage) 
                           ? diag::objc_getter_for_nonobjc_property
                           : diag::objc_getter_for_nonobjc_subscript)
                      : (isa<VarDecl>(storage)
                           ? diag::objc_setter_for_nonobjc_property
                           : diag::objc_setter_for_nonobjc_subscript);
  
            diagnose(FD->getLoc(), error);
            describeObjCReason(*this, AFD, Reason);
          }
          return false;
        }
      } else {
        unsigned ExpectedParamPatterns = 1;
        if (FD->getImplicitSelfDecl())
          ExpectedParamPatterns++;
        if (FD->getBodyParamPatterns().size() != ExpectedParamPatterns) {
          if (Diagnose) {
            diagnose(AFD->getLoc(), diag::objc_invalid_on_func_curried,
                     getObjCDiagnosticAttrKind(Reason));
            describeObjCReason(*this, AFD, Reason);
          }
          return false;
        }
      }
  
      // willSet/didSet implementations are never exposed to objc, they are always
      // directly dispatched from the synthesized setter.
      if (FD->isObservingAccessor()) {
        if (Diagnose) {
          diagnose(AFD->getLoc(), diag::objc_observing_accessor);
          describeObjCReason(*this, AFD, Reason);
        }
        return false;
      }
    }
  
    // As a special case, an initializer with a single, named parameter of type
    // '()' is always representable in Objective-C. This allows us to cope with
    // zero-parameter methods with selectors that are longer than "init". For
    // example, this allows:
    //
    // \code
    // class Foo {
    //   @objc init(malice: ()) { } // selector is "initWithMalice"
    // }
    // \endcode
    bool isSpecialInit = false;
    if (auto init = dyn_cast<ConstructorDecl>(AFD))
      isSpecialInit = init->isObjCZeroParameterWithLongSelector();
  
    if (!isSpecialInit &&
        !isParamPatternRepresentableInObjC(*this, AFD,
                                           AFD->getBodyParamPatterns()[1],
                                           Reason)) {
      if (!Diagnose) {
        // Return as soon as possible if we are not producing diagnostics.
        return false;
      }
    }
  
    if (auto FD = dyn_cast<FuncDecl>(AFD)) {
      Type ResultType = FD->getResultType();
      if (!ResultType->isVoid() && !isRepresentableInObjC(FD, ResultType)) {
        if (Diagnose) {
          diagnose(AFD->getLoc(), diag::objc_invalid_on_func_result_type,
                   getObjCDiagnosticAttrKind(Reason));
          SourceRange Range =
              FD->getBodyResultTypeLoc().getTypeRepr()->getSourceRange();
          diagnoseTypeNotRepresentableInObjC(FD, ResultType, Range);
          describeObjCReason(*this, FD, Reason);
        }
        return false;
      }
    }
  
    // Throwing functions must map to a particular error convention.
    if (AFD->isBodyThrowing()) {
      DeclContext *dc = const_cast<AbstractFunctionDecl *>(AFD);
      SourceLoc throwsLoc;
      Type resultType;
  
      const ConstructorDecl *ctor = nullptr;
      if (auto func = dyn_cast<FuncDecl>(AFD)) {
        resultType = func->getResultType();
        throwsLoc = func->getThrowsLoc();
      } else {
        ctor = cast<ConstructorDecl>(AFD);
        throwsLoc = ctor->getThrowsLoc();
      }
  
      ForeignErrorConvention::Kind kind;
      CanType errorResultType;
      Type optOptionalType;
      if (ctor) {
        // Initializers always use the nil result convention.
        kind = ForeignErrorConvention::NilResult;
  
        // Only non-failing initializers can throw.
        if (ctor->getFailability() != OTK_None) {
          if (Diagnose) {
            diagnose(AFD->getLoc(), diag::objc_invalid_on_failing_init,
                     getObjCDiagnosticAttrKind(Reason))
              .highlight(throwsLoc);
            describeObjCReason(*this, AFD, Reason);
          }
  
          return false;
        }
      } else if (resultType->isVoid()) {
        // Functions that return nothing (void) can be throwing; they indicate
        // failure with a 'false' result.
        kind = ForeignErrorConvention::ZeroResult;
        errorResultType = Context.getBoolDecl()
                            ->getDeclaredInterfaceType()->getCanonicalType();
      } else if (!resultType->getAnyOptionalObjectType() &&
                 isBridgedToObjectiveCClass(dc, resultType)) {
        // Functions that return a (non-optional) type bridged to Objective-C
        // can be throwing; they indicate failure with a nil result.
        kind = ForeignErrorConvention::NilResult;
      } else if ((optOptionalType = resultType->getAnyOptionalObjectType()) &&
                 isBridgedToObjectiveCClass(dc, optOptionalType)) {
        // Cannot return an optional bridged type, because 'nil' is reserved
        // to indicate failure. Call this out in a separate diagnostic.
        if (Diagnose) {
          diagnose(AFD->getLoc(),
                   diag::objc_invalid_on_throwing_optional_result,
                   getObjCDiagnosticAttrKind(Reason),
                   resultType)
            .highlight(throwsLoc);
          describeObjCReason(*this, AFD, Reason);
        }
        return false;
      } else {
        // Other result types are not permitted.
        if (Diagnose) {
          diagnose(AFD->getLoc(),
                   diag::objc_invalid_on_throwing_result,
                   getObjCDiagnosticAttrKind(Reason),
                   resultType)
            .highlight(throwsLoc);
          describeObjCReason(*this, AFD, Reason);
        }
        return false;
      }
  
      // The error type is always AutoreleasingUnsafeMutablePointer<NSError?>.
      Type errorParameterType = getNSErrorType(dc);
      if (errorParameterType) {
        errorParameterType = OptionalType::get(errorParameterType);
        errorParameterType
          = BoundGenericType::get(
              Context.getAutoreleasingUnsafeMutablePointerDecl(),
              nullptr,
              errorParameterType);
      }
  
      // Determine the parameter index at which the error will go.
      unsigned errorParameterIndex;
      bool foundErrorParameterIndex = false;
  
      // If there is an explicit @objc attribute with a name, look for
      // the "error" selector piece.
      if (auto objc = AFD->getAttrs().getAttribute<ObjCAttr>()) {
        if (auto objcName = objc->getName()) {
          auto selectorPieces = objcName->getSelectorPieces();
          for (unsigned i = selectorPieces.size(); i > 0; --i) {
            // If the selector piece is "error", this is the location of
            // the error parameter.
            auto piece = selectorPieces[i-1];
            if (piece == Context.Id_error) {
              errorParameterIndex = i-1;
              foundErrorParameterIndex = true;
              break;
            }
  
            // If the first selector piece ends with "Error", it's here.
            if (i == 1 && camel_case::getLastWord(piece.str()) == "Error") {
              errorParameterIndex = i-1;
              foundErrorParameterIndex = true;
              break;
            }
          }
        }
      }
  
      // If the selector did not provide an index for the error, find
      // the last parameter that is not a trailing closure.
      if (!foundErrorParameterIndex) {
        const Pattern *paramPattern = AFD->getBodyParamPatterns()[1];
        if (auto *tuple = dyn_cast<TuplePattern>(paramPattern)) {
          errorParameterIndex = tuple->getNumElements();
          while (errorParameterIndex > 0 &&
                 isTrailingClosure(
                   tuple->getElement(errorParameterIndex - 1).getPattern()
                     ->getType()))
            --errorParameterIndex;
        } else {
          auto paren = cast<ParenPattern>(paramPattern);
          errorParameterIndex
            = isTrailingClosure(paren->getSubPattern()->getType()) ? 0 : 1;
        }
      }
  
      // Form the error convention.
      CanType canErrorParameterType;
      if (errorParameterType)
        canErrorParameterType = errorParameterType->getCanonicalType();
      switch (kind) {
      case ForeignErrorConvention::ZeroResult:
        errorConvention = ForeignErrorConvention::getZeroResult(
                            errorParameterIndex,
                            ForeignErrorConvention::IsNotOwned,
                            ForeignErrorConvention::IsNotReplaced,
                            canErrorParameterType,
                            errorResultType);
        break;
  
      case ForeignErrorConvention::NonZeroResult:
        errorConvention = ForeignErrorConvention::getNonZeroResult(
                            errorParameterIndex,
                            ForeignErrorConvention::IsNotOwned,
                            ForeignErrorConvention::IsNotReplaced,
                            canErrorParameterType,
                            errorResultType);
        break;
  
      case ForeignErrorConvention::ZeroPreservedResult:
        errorConvention = ForeignErrorConvention::getZeroPreservedResult(
                            errorParameterIndex,
                            ForeignErrorConvention::IsNotOwned,
                            ForeignErrorConvention::IsNotReplaced,
                            canErrorParameterType);
        break;
  
      case ForeignErrorConvention::NilResult:
        errorConvention = ForeignErrorConvention::getNilResult(
                            errorParameterIndex,
                            ForeignErrorConvention::IsNotOwned,
                            ForeignErrorConvention::IsNotReplaced,
                            canErrorParameterType);
        break;
  
      case ForeignErrorConvention::NonNilError:
        errorConvention = ForeignErrorConvention::getNilResult(
                            errorParameterIndex,
                            ForeignErrorConvention::IsNotOwned,
                            ForeignErrorConvention::IsNotReplaced,
                            canErrorParameterType);
        break;
      }
    }
  
    return true;
  }
  
  bool TypeChecker::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    if (VD->isInvalid())
      return false;
  
    Type T = VD->getType();
    if (auto *RST = T->getAs<ReferenceStorageType>()) {
      // In-memory layout of @weak and @unowned does not correspond to anything
      // in Objective-C, but this does not really matter here, since Objective-C
      // uses getters and setters to operate on the property.
      // Because of this, look through @weak and @unowned.
      T = RST->getReferentType();
    }
    bool Result = isRepresentableInObjC(VD->getDeclContext(), T);
    bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
  
    if (Result && checkObjCInExtensionContext(*this, VD, Diagnose))
      return false;
  
    if (checkObjCInForeignClassContext(*this, VD, Reason))
      return false;
  
    if (!Diagnose || Result)
      return Result;
  
    SourceRange TypeRange = VD->getTypeSourceRangeForDiagnostics();
    diagnose(VD->getLoc(), diag::objc_invalid_on_var,
             getObjCDiagnosticAttrKind(Reason))
        .highlight(TypeRange);
    diagnoseTypeNotRepresentableInObjC(VD->getDeclContext(), VD->getType(),
                                       TypeRange);
    describeObjCReason(*this, VD, Reason);
  
    return Result;
  }
  
  bool TypeChecker::isRepresentableInObjC(const SubscriptDecl *SD,
                                          ObjCReason Reason) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    bool Diagnose = (Reason != ObjCReason::DoNotDiagnose);
  
    if (checkObjCInForeignClassContext(*this, SD, Reason))
      return false;
  
    // Figure out the type of the indices.
    Type IndicesType = SD->getIndicesType();
    if (auto TupleTy = IndicesType->getAs<TupleType>()) {
      if (TupleTy->getNumElements() == 1 && !TupleTy->getElement(0).isVararg())
        IndicesType = TupleTy->getElementType(0);
    }
  
    bool IndicesResult = isRepresentableInObjC(SD->getDeclContext(), IndicesType);
    bool ElementResult = isRepresentableInObjC(SD->getDeclContext(),
                                               SD->getElementType());
    bool Result = IndicesResult && ElementResult;
  
    if (Result && checkObjCInExtensionContext(*this, SD, Diagnose))
      return false;
  
    // Make sure we know how to map the selector appropriately.
    if (Result && SD->getObjCSubscriptKind(this) == ObjCSubscriptKind::None) {
      SourceRange IndexRange = SD->getIndices()->getSourceRange();
      diagnose(SD->getLoc(), diag::objc_invalid_subscript_key_type,
               getObjCDiagnosticAttrKind(Reason), IndicesType)
        .highlight(IndexRange);
      return false;
    }
  
    if (!Diagnose || Result)
      return Result;
  
    SourceRange TypeRange;
    if (!IndicesResult)
      TypeRange = SD->getIndices()->getSourceRange();
    else
      TypeRange = SD->getElementTypeLoc().getSourceRange();
    diagnose(SD->getLoc(), diag::objc_invalid_on_subscript,
             getObjCDiagnosticAttrKind(Reason))
      .highlight(TypeRange);
  
    diagnoseTypeNotRepresentableInObjC(SD->getDeclContext(),
                                       !IndicesResult? IndicesType
                                                     : SD->getElementType(),
                                       TypeRange);
    describeObjCReason(*this, SD, Reason);
  
    return Result;
  }
  
  /// True if T is representable as a non-nullable ObjC pointer type.
  static bool isAnyObjCRepresentableObjectType(Type T) {
    // Look through a single level of metatype.
    if (auto MTT = T->getAs<AnyMetatypeType>())
      T = MTT->getInstanceType();
  
    if (auto dynSelf = T->getAs<DynamicSelfType>())
      T = dynSelf->getSelfType();
  
    if (auto *CT = T->getAs<ClassType>())
      return CT->getDecl()->isObjC();
    return T->isObjCExistentialType();
  }
  
  /// True if T is representable as an ObjC pointer type, nullable or otherwise.
  static bool isNullableObjCRepresentableObjectType(Type T) {
    // Look through a single layer of optional type.
    if (auto valueType = T->getAnyOptionalObjectType()) {
      T = valueType;
    }
    return isAnyObjCRepresentableObjectType(T);
  }
  
  bool TypeChecker::isTriviallyRepresentableInObjC(const DeclContext *DC,
                                                   Type T) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    // Look through one level of optional type, but remember that we did.
    bool wasOptional = false;
    if (auto valueType = T->getAnyOptionalObjectType()) {
      T = valueType;
      wasOptional = true;
    }
  
    // T can be represented in Objective-C if T is an @objc class or protocol.
    if (isAnyObjCRepresentableObjectType(T))
      return true;
  
    auto NTD = T->getAnyNominal();
  
    // Unmanaged<T> can be represented in Objective-C if T is an @objc class
    // or protocol.
    if (NTD == Context.getUnmanagedDecl()) {
      auto BGT = T->getAs<BoundGenericType>();
      if (!BGT)
        return false;
      assert(BGT->getGenericArgs().size() == 1);
      return isAnyObjCRepresentableObjectType(BGT->getGenericArgs().front());
    }
  
    // TODO: maybe Optional<UnsafeMutablePointer<T>> should be okay?
    if (wasOptional)
      return false;
  
    if (NTD) {
      // If the type was imported from Clang, it is representable in Objective-C.
      if (NTD->hasClangNode())
        return true;
      
      // If the type is @objc, it is representable in Objective-C.
      if (NTD->isObjC())
        return true;
  
      // Pointers may be representable in ObjC.
      PointerTypeKind PTK;
      if (auto pointerElt = T->getAnyPointerElementType(PTK)) {
        switch (PTK) {
        case PTK_UnsafeMutablePointer:
        case PTK_UnsafePointer: {
          // An UnsafeMutablePointer<T> or UnsafePointer<T> is
          // representable in Objective-C if T is a trivially
          // representable type or Void.
          return pointerElt->isEqual(Context.TheEmptyTupleType)
            || isTriviallyRepresentableInObjC(DC, pointerElt);
        }
        case PTK_AutoreleasingUnsafeMutablePointer: {
          // An AutoreleasingUnsafeMutablePointer<T> is representable in ObjC if T
          // is a (potentially optional) ObjC pointer type.
          return isNullableObjCRepresentableObjectType(pointerElt);
        }
        }
      }
  
    }
  
    // If it's a mapped type, it's representable.
    fillObjCRepresentableTypeCache(DC);
    if (ObjCMappedTypes.count(T->getCanonicalType()))
      return true;
  
    return false;
  }
  
  static bool
  isObjCRepresentableCollection(TypeChecker &TC, const DeclContext *DC, Type T);
  
  static bool
  isElementRepresentableInObjC(TypeChecker &TC, const DeclContext *DC, Type T) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    // ImplicitlyUnwrappedOptional is marked bridgeable to Objective-C, but
    // it's not something you can put in API signatures.
    if (T->getAnyOptionalObjectType())
      return false;
  
    if (isAnyObjCRepresentableObjectType(T))
      return true;
  
    if (isObjCRepresentableCollection(TC, DC, T))
      return true;
  
    if (auto fnTy = T->getAs<AnyFunctionType>())
      return fnTy->getRepresentation() == FunctionTypeRepresentation::Block;
  
    if (!T->getAs<BoundGenericType>()) {
      // Don't check this path for collections and other things that are only
      // conditionally bridged to Objective-C.
      ProtocolDecl *bridgingProto =
          TC.getProtocol({}, KnownProtocolKind::ObjectiveCBridgeable);
      if (bridgingProto &&
          TC.conformsToProtocol(T, bridgingProto, const_cast<DeclContext *>(DC),
                                ConformanceCheckOptions())) {
        return true;
      }
    }
  
    return false;
  }
  
  static bool
  isObjCRepresentableCollection(TypeChecker &TC, const DeclContext *DC, Type T) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    auto boundGeneric = T->getAs<BoundGenericType>();
    if (!boundGeneric)
      return false;
  
    // Array<T> is representable when T is bridged to Objective-C.
    if (auto arrayDecl = TC.Context.getArrayDecl()) {
      if (boundGeneric->getDecl() == arrayDecl) {
        auto elementType = boundGeneric->getGenericArgs()[0];
        return isElementRepresentableInObjC(TC, DC, elementType);
      }
    }
  
    // Dictionary<K, V> is representable when K and V are bridged to Objective-C.
    if (auto dictDecl = TC.Context.getDictionaryDecl()) {
      if (boundGeneric->getDecl() == dictDecl) {
        // The key type must be bridged to Objective-C.
        auto keyType = boundGeneric->getGenericArgs()[0];
        if (!isElementRepresentableInObjC(TC, DC, keyType))
          return false;
  
        // The value type must be bridged to Objective-C.
        auto valueType = boundGeneric->getGenericArgs()[1];
        if (!isElementRepresentableInObjC(TC, DC, valueType))
          return false;
  
        return true;
      }
    }
  
    // Set<T> is representable when T is bridged to Objective-C.
    if (auto setDecl = TC.Context.getSetDecl()) {
      if (boundGeneric->getDecl() == setDecl) {
        auto elementType = boundGeneric->getGenericArgs()[0];
        return isElementRepresentableInObjC(TC, DC, elementType);
      }
    }
  
    return false;
  }
  
  bool TypeChecker::isRepresentableInObjC(const DeclContext *DC, Type T) {
    // If you change this function, you must add or modify a test in PrintAsObjC.
  
    if (isTriviallyRepresentableInObjC(DC, T))
      return true;
  
    // Look through one level of optional type, but remember that we did.
    bool wasOptional = false;
    if (auto valueType = T->getAnyOptionalObjectType()) {
      T = valueType;
      wasOptional = true;
    }
  
    if (auto FT = T->getAs<FunctionType>()) {
      switch (FT->getRepresentation()) {
      case AnyFunctionType::Representation::Thin:
        return false;
      case AnyFunctionType::Representation::Swift:
      case AnyFunctionType::Representation::Block:
      case AnyFunctionType::Representation::CFunctionPointer:
        break;
      }
      
      Type Input = FT->getInput();
      if (auto InputTuple = Input->getAs<TupleType>()) {
        for (auto &Elt : InputTuple->getElements()) {
          if (Elt.isVararg())
            return false;
          if (!isRepresentableInObjC(DC, Elt.getType()))
            return false;
        }
      } else if (!isRepresentableInObjC(DC, Input)) {
        return false;
      }
  
      Type Result = FT->getResult();
      if (!Result->isVoid() && !isRepresentableInObjC(DC, Result))
        return false;
  
      if (FT->getExtInfo().throws())
        return false;
  
      return true;
    }
  
    if (isObjCRepresentableCollection(*this, DC, T))
      return true;
  
    // Check to see if this is a bridged type.  Note that some bridged
    // types are representable, but their optional type is not.
    fillObjCRepresentableTypeCache(DC);
    auto iter = ObjCRepresentableTypes.find(T->getCanonicalType());
    if (iter != ObjCRepresentableTypes.end()) {
      if (wasOptional && !iter->second)
        return false;
      return true;
    }
  
    return false;
  }
  
  void TypeChecker::diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
                                                       Type T,
                                                       SourceRange TypeRange) {
    // Special diagnostic for tuples.
    if (T->is<TupleType>()) {
      if (T->isVoid())
        diagnose(TypeRange.Start, diag::not_objc_empty_tuple)
            .highlight(TypeRange);
      else
        diagnose(TypeRange.Start, diag::not_objc_tuple)
            .highlight(TypeRange);
      return;
    }
  
    // Special diagnostic for classes.
    if (auto *CT = T->getAs<ClassType>()) {
      if (!CT->getDecl()->isObjC())
        diagnose(TypeRange.Start, diag::not_objc_swift_class)
            .highlight(TypeRange);
      return;
    }
  
    // Special diagnostic for structs.
    if (T->is<StructType>()) {
      diagnose(TypeRange.Start, diag::not_objc_swift_struct)
          .highlight(TypeRange);
      return;
    }
  
    // Special diagnostic for enums.
    if (T->is<EnumType>()) {
      diagnose(TypeRange.Start, diag::not_objc_swift_enum)
          .highlight(TypeRange);
      return;
    }
  
    // Special diagnostic for protocols and protocol compositions.
    SmallVector<ProtocolDecl *, 4> Protocols;
    if (T->isExistentialType(Protocols)) {
      if (Protocols.empty()) {
        // protocol<> is not @objc.
        diagnose(TypeRange.Start, diag::not_objc_empty_protocol_composition);
        return;
      }
      // Find a protocol that is not @objc.
      for (auto PD : Protocols) {
        if (!PD->isObjC()) {
          diagnose(TypeRange.Start, diag::not_objc_protocol,
                   PD->getDeclaredType());
          return;
        }
      }
      return;
    }
  
    if (T->is<ArchetypeType>()) {
      diagnose(TypeRange.Start, diag::not_objc_generic_type_param)
          .highlight(TypeRange);
      return;
    }
  
    if (auto fnTy = T->getAs<FunctionType>()) {
      if (fnTy->getExtInfo().throws() ) {
        diagnose(TypeRange.Start, diag::not_objc_function_type_throwing)
          .highlight(TypeRange);
        return;
      }
  
      diagnose(TypeRange.Start, diag::not_objc_function_type_param)
        .highlight(TypeRange);
      return;
    }
  }
  
  static void
  lookupAndAddRepresentableType(TypeChecker &TC,
                                Module *stdlib,
                                Identifier nativeName,
                                bool isOptionalRepresentable,
                                llvm::DenseMap<CanType, bool> &types) {
    auto nativeType = lookupUniqueTypeInLibrary(TC, stdlib, nativeName);
    if (!nativeType) return;
  
    types.insert({nativeType, isOptionalRepresentable});
  }
  
  void TypeChecker::fillObjCRepresentableTypeCache(const DeclContext *DC) {
    if (!ObjCMappedTypes.empty())
      return;
  
    SmallVector<Identifier, 32> StdlibTypeNames;
  
    StdlibTypeNames.push_back(Context.getIdentifier("COpaquePointer"));
  #define MAP_BUILTIN_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
    StdlibTypeNames.push_back(Context.getIdentifier(#SWIFT_TYPE_NAME));
  #include "swift/ClangImporter/BuiltinMappedTypes.def"
  
    Module *Stdlib = getStdlibModule(DC);
    lookupAndAddLibraryTypes(*this, Stdlib, StdlibTypeNames, ObjCMappedTypes);
  
    StdlibTypeNames.clear();
  #define MAP_BUILTIN_TYPE(_, __)
  #define MAP_BUILTIN_INTEGER_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
    StdlibTypeNames.push_back(Context.getIdentifier(#SWIFT_TYPE_NAME));
  #include "swift/ClangImporter/BuiltinMappedTypes.def"
    lookupAndAddLibraryTypes(*this, Stdlib, StdlibTypeNames, CIntegerTypes);
  
  #define BRIDGE_TYPE(BRIDGED_MODULE, BRIDGED_TYPE,                          \
                      NATIVE_MODULE, NATIVE_TYPE, OPTIONAL_IS_BRIDGED)       \
    if (Context.getIdentifier(#NATIVE_MODULE) == Context.StdlibModuleName) { \
      lookupAndAddRepresentableType(*this, Stdlib,                           \
                                    Context.getIdentifier(#NATIVE_TYPE),     \
                                    OPTIONAL_IS_BRIDGED,                     \
                                    ObjCRepresentableTypes);                 \
    }
  #include "swift/SIL/BridgedTypes.def"
  
    Identifier ID_Darwin = Context.Id_Darwin;
    if (auto DarwinModule = Context.getLoadedModule(ID_Darwin)) {
      StdlibTypeNames.clear();
      StdlibTypeNames.push_back(Context.getIdentifier("DarwinBoolean"));
      lookupAndAddLibraryTypes(*this, DarwinModule, StdlibTypeNames,
                               ObjCMappedTypes);
    }
  
    Identifier ID_ObjectiveC = Context.Id_ObjectiveC;
    if (auto ObjCModule = Context.getLoadedModule(ID_ObjectiveC)) {
      StdlibTypeNames.clear();
      StdlibTypeNames.push_back(Context.getIdentifier("Selector"));
      StdlibTypeNames.push_back(Context.getIdentifier("ObjCBool"));
      StdlibTypeNames.push_back(Context.getIdentifier("NSZone"));
      lookupAndAddLibraryTypes(*this, ObjCModule, StdlibTypeNames,
                               ObjCMappedTypes);
    }
  
    Identifier ID_CoreGraphics = Context.getIdentifier("CoreGraphics");
    if (auto CoreGraphicsModule = Context.getLoadedModule(ID_CoreGraphics)) {
      StdlibTypeNames.clear();
      StdlibTypeNames.push_back(Context.getIdentifier("CGFloat"));
      lookupAndAddLibraryTypes(*this, CoreGraphicsModule, StdlibTypeNames,
                               ObjCMappedTypes);
    }
  
    Identifier ID_Foundation = Context.Id_Foundation;
    if (auto FoundationModule = Context.getLoadedModule(ID_Foundation)) {
      StdlibTypeNames.clear();
      StdlibTypeNames.push_back(Context.getIdentifier("NSErrorPointer"));
      lookupAndAddLibraryTypes(*this, FoundationModule, StdlibTypeNames,
                               ObjCMappedTypes);
    }
    
    // Pull SIMD types of size 2...4 from the SIMD module, if it exists.
    Identifier ID_SIMD = Context.Id_simd;
    if (auto SIMDModule = Context.getLoadedModule(ID_SIMD)) {
      StdlibTypeNames.clear();
  #define MAP_SIMD_TYPE(BASENAME, __)                                      \
      {                                                                    \
        char name[] = #BASENAME "0";                                       \
        for (unsigned i = 2; i <= SWIFT_MAX_IMPORTED_SIMD_ELEMENTS; ++i) { \
          *(std::end(name) - 2) = '0' + i;                                 \
          StdlibTypeNames.push_back(Context.getIdentifier(name));          \
        }                                                                  \
      }
  #include "swift/ClangImporter/SIMDMappedTypes.def"
      lookupAndAddLibraryTypes(*this, SIMDModule, StdlibTypeNames,
                               ObjCMappedTypes);
    }
  }
  
  namespace {
  
  class UnsupportedProtocolVisitor
    : public TypeReprVisitor<UnsupportedProtocolVisitor>, public ASTWalker
  {
    TypeChecker &TC;
    SmallPtrSet<ProtocolDecl *, 4> Diagnosed;
  
  public:
    UnsupportedProtocolVisitor(TypeChecker &tc) : TC(tc) { }
  
    SmallPtrSet<ProtocolDecl *, 4> &getDiagnosedProtocols() { return Diagnosed; }
  
    bool walkToTypeReprPre(TypeRepr *T) {
      visit(T);
      return true;
    }
  
    void visitIdentTypeRepr(IdentTypeRepr *T) {
      auto comp = T->getComponentRange().back();
      if (auto proto = dyn_cast_or_null<ProtocolDecl>(comp->getBoundDecl())) {
        if (!proto->existentialTypeSupported(&TC)) {
          TC.diagnose(comp->getIdLoc(), diag::unsupported_existential_type,
                      proto->getName());
          Diagnosed.insert(proto);
        }
  
        return;
      }
    }
  };
  
  }
  
  void TypeChecker::checkUnsupportedProtocolType(Decl *decl) {
    if (!decl || decl->isInvalid())
      return;
  
    // Global type aliases are okay.
    if (isa<TypeAliasDecl>(decl) &&
        decl->getDeclContext()->isModuleScopeContext())
      return;
  
    // Non-typealias type declarations are okay.
    if (isa<TypeDecl>(decl) && !isa<TypeAliasDecl>(decl))
      return;
  
    // Extensions are okay.
    if (isa<ExtensionDecl>(decl))
      return;
  
    UnsupportedProtocolVisitor visitor(*this);
    decl->walk(visitor);
    if (auto valueDecl = dyn_cast<ValueDecl>(decl)) {
      if (auto type = valueDecl->getType()) {
        type.findIf([&](Type type) -> bool {
          SmallVector<ProtocolDecl*, 2> protocols;
          if (type->isExistentialType(protocols)) {
            for (auto *proto : protocols) {
              if (proto->existentialTypeSupported(this))
                continue;
  
              if (visitor.getDiagnosedProtocols().insert(proto).second) {
                diagnose(valueDecl->getLoc(),
                         diag::unsupported_existential_type,
                         proto->getName());
              }
            }
          }
  
          return false;
        });
      }
    }
  }
  
  void TypeChecker::checkUnsupportedProtocolType(Stmt *stmt) {
    if (!stmt)
      return;
  
    UnsupportedProtocolVisitor visitor(*this);
    stmt->walk(visitor);
  }
  