示例#1
0
/// If the candidate set has been narrowed to a single parameter or single
/// archetype that has argument type errors, diagnose that error and
/// return true.
bool CalleeCandidateInfo::diagnoseGenericParameterErrors(Expr *badArgExpr) {
  TypeChecker &TC = CS.TC;
  Type argType = CS.getType(badArgExpr);
  
  // FIXME: For protocol argument types, could add specific error
  // similar to could_not_use_member_on_existential.
  if (argType->hasTypeVariable() || argType->is<ProtocolType>() ||
      argType->is<ProtocolCompositionType>())
    return false;
  
  bool foundFailure = false;
  TypeSubstitutionMap archetypesMap;
  
  if (!findGenericSubstitutions(failedArgument.declContext,
                                failedArgument.parameterType,
                                argType, archetypesMap))
    return false;
  
  auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * {
    auto paramType = archetype->getInterfaceType();
    
    if (auto *GTPT = paramType->getAs<GenericTypeParamType>())
      return GTPT->getDecl();
    
    if (auto *DMT = paramType->getAs<DependentMemberType>())
      return DMT->getAssocType();
    
    return nullptr;
  };
  
  auto describeGenericType = [&](ValueDecl *genericParam,
                                 bool includeName = false) -> std::string {
    if (!genericParam)
      return "";
    
    Decl *parent = nullptr;
    if (auto *AT = dyn_cast<AssociatedTypeDecl>(genericParam)) {
      parent = AT->getProtocol();
    } else {
      auto *dc = genericParam->getDeclContext();
      parent = dc->getInnermostDeclarationDeclContext();
    }
    
    if (!parent)
      return "";
    
    llvm::SmallString<64> result;
    llvm::raw_svector_ostream OS(result);
    
    OS << Decl::getDescriptiveKindName(genericParam->getDescriptiveKind());
    
    if (includeName && genericParam->hasName())
      OS << " '" << genericParam->getBaseName() << "'";
    
    OS << " of ";
    OS << Decl::getDescriptiveKindName(parent->getDescriptiveKind());
    if (auto *decl = dyn_cast<ValueDecl>(parent)) {
      if (decl->hasName())
        OS << " '" << decl->getFullName() << "'";
    }
    
    return OS.str();
  };
  
  for (auto pair : archetypesMap) {
    auto paramArchetype = pair.first->castTo<ArchetypeType>();
    auto substitution = pair.second;
    
    // FIXME: Add specific error for not subclass, if the archetype has a superclass?
    
    // Check for optional near miss.
    if (auto argOptType = substitution->getOptionalObjectType()) {
      if (isSubstitutableFor(argOptType, paramArchetype, CS.DC)) {
        CS.TC.diagnose(badArgExpr->getLoc(), diag::missing_unwrap_optional,
                       argType);
        foundFailure = true;
        break;
      }
    }
    
    for (auto proto : paramArchetype->getConformsTo()) {
      if (!CS.TC.conformsToProtocol(substitution, proto, CS.DC,
                                    ConformanceCheckFlags::InExpression)) {
        if (substitution->isEqual(argType)) {
          CS.TC.diagnose(badArgExpr->getLoc(),
                         diag::cannot_convert_argument_value_protocol,
                         substitution, proto->getDeclaredType());
        } else {
          CS.TC.diagnose(badArgExpr->getLoc(),
                         diag::cannot_convert_partial_argument_value_protocol,
                         argType, substitution, proto->getDeclaredType());
        }
        foundFailure = true;
        break;
      }
    }
    
    if (auto *argArchetype = substitution->getAs<ArchetypeType>()) {
      // Produce this diagnostic only if the names
      // of the generic parameters are the same.
      if (argArchetype->getName() != paramArchetype->getName())
        continue;
      
      auto *paramDecl = getGenericTypeDecl(paramArchetype);
      auto *argDecl = getGenericTypeDecl(argArchetype);
      
      if (!paramDecl || !argDecl)
        continue;
      
      TC.diagnose(badArgExpr->getLoc(),
                  diag::cannot_convert_argument_value_generic, argArchetype,
                  describeGenericType(argDecl), paramArchetype,
                  describeGenericType(paramDecl));
      
      TC.diagnose(paramDecl, diag::descriptive_generic_type_declared_here,
                  describeGenericType(paramDecl, true));
      
      TC.diagnose(argDecl, diag::descriptive_generic_type_declared_here,
                  describeGenericType(argDecl, true));
      
      foundFailure = true;
      break;
    }
  }
  
  return foundFailure;
}