Ejemplo n.º 1
0
static bool diagnoseUnwrap(ConstraintSystem &CS, Expr *expr, Type type) {
  Type unwrappedType = type->getOptionalObjectType();
  if (!unwrappedType)
    return false;

  CS.TC.diagnose(expr->getLoc(), diag::optional_not_unwrapped, type,
                 unwrappedType);

  // If the expression we're unwrapping is the only reference to a
  // local variable whose type isn't explicit in the source, then
  // offer unwrapping fixits on the initializer as well.
  if (auto declRef = dyn_cast<DeclRefExpr>(expr)) {
    if (auto varDecl = dyn_cast<VarDecl>(declRef->getDecl())) {

      bool singleUse = false;
      AbstractFunctionDecl *AFD = nullptr;
      if (auto contextDecl = varDecl->getDeclContext()->getAsDecl()) {
        if ((AFD = dyn_cast<AbstractFunctionDecl>(contextDecl))) {
          auto checker = VarDeclMultipleReferencesChecker(varDecl);
          AFD->getBody()->walk(checker);
          singleUse = checker.referencesCount() == 1;
        }
      }

      PatternBindingDecl *binding = varDecl->getParentPatternBinding();
      if (singleUse && binding && binding->getNumPatternEntries() == 1 &&
          varDecl->getTypeSourceRangeForDiagnostics().isInvalid()) {

        Expr *initializer = varDecl->getParentInitializer();
        if (auto declRefExpr = dyn_cast<DeclRefExpr>(initializer)) {
          if (declRefExpr->getDecl()->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>()) {
            CS.TC.diagnose(declRefExpr->getLoc(), diag::unwrap_iuo_initializer, type);
          }
        }

        auto fnTy = AFD->getInterfaceType()->castTo<AnyFunctionType>();
        bool voidReturn = fnTy->getResult()->isEqual(TupleType::getEmpty(CS.DC->getASTContext()));

        auto diag = CS.TC.diagnose(varDecl->getLoc(), diag::unwrap_with_guard);
        diag.fixItInsert(binding->getStartLoc(), "guard ");
        if (voidReturn) {
          diag.fixItInsertAfter(binding->getEndLoc(), " else { return }");
        } else {
          diag.fixItInsertAfter(binding->getEndLoc(), " else { return <"
                                "#default value#" "> }");
        }
        diag.flush();

        offerDefaultValueUnwrapFixit(CS.TC, varDecl->getDeclContext(),
                                     initializer);
        offerForceUnwrapFixit(CS, initializer);
      }
    }
  }

  offerDefaultValueUnwrapFixit(CS.TC, CS.DC, expr);
  offerForceUnwrapFixit(CS, expr);
  return true;
}
Ejemplo n.º 2
0
/// When we see an expression in a TopLevelCodeDecl in the REPL, process it,
/// adding the proper decls back to the top level of the file.
void REPLChecker::processREPLTopLevelExpr(Expr *E) {
  CanType T = E->getType()->getCanonicalType();

  // Don't try to print invalid expressions, module exprs, or void expressions.
  if (T->hasError() || isa<ModuleType>(T) || T->isVoid())
    return;

  // Okay, we need to print this expression.  We generally do this by creating a
  // REPL metavariable (e.g. r4) to hold the result, so it can be referred to
  // in the future.  However, if this is a direct reference to a decl (e.g. "x")
  // then don't create a repl metavariable.
  if (VarDecl *d = getObviousDeclFromExpr(E)) {
    generatePrintOfExpression(d->getName().str(), E);
    return;
  }

  // Remove the expression from being in the list of decls to execute, we're
  // going to reparent it.
  auto TLCD = cast<TopLevelCodeDecl>(SF.Decls.back());

  E = TC.coerceToRValue(E);

  // Create the meta-variable, let the typechecker name it.
  Identifier name = TC.getNextResponseVariableName(SF.getParentModule());
  VarDecl *vd = new (Context) VarDecl(/*IsStatic*/false,
                                      VarDecl::Specifier::Let,
                                      /*IsCaptureList*/false, E->getStartLoc(),
                                      name, E->getType(), &SF);
  vd->setInterfaceType(E->getType());
  SF.Decls.push_back(vd);

  // Create a PatternBindingDecl to bind the expression into the decl.
  Pattern *metavarPat = new (Context) NamedPattern(vd);
  metavarPat->setType(E->getType());

  PatternBindingDecl *metavarBinding = PatternBindingDecl::create(
      Context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::None,
      /*VarLoc*/ E->getStartLoc(), metavarPat, /*EqualLoc*/ SourceLoc(), E,
      TLCD);

  // Overwrite the body of the existing TopLevelCodeDecl.
  TLCD->setBody(BraceStmt::create(Context,
                                  metavarBinding->getStartLoc(),
                                  ASTNode(metavarBinding),
                                  metavarBinding->getEndLoc(),
                                  /*implicit*/true));

  // Finally, print the variable's value.
  E = TC.buildCheckedRefExpr(vd, &SF, DeclNameLoc(E->getStartLoc()),
                             /*Implicit=*/true);
  generatePrintOfExpression(vd->getName().str(), E);
}
Ejemplo n.º 3
0
/// processREPLTopLevelPatternBinding - When we see a new PatternBinding parsed
/// into the REPL, process it by generating code to print it out.
void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) {
  // If there is no initializer for the new variable, don't auto-print it.
  // This would just cause a confusing definite initialization error.  Some
  // day we will do some high level analysis of uninitialized variables
  // (rdar://15157729) but until then, output a specialized error.
  unsigned entryIdx = 0U-1;
  for (auto patternEntry : PBD->getPatternList()) {
    ++entryIdx;
    if (!patternEntry.getInit()) {
      TC.diagnose(PBD->getStartLoc(), diag::repl_must_be_initialized);
      continue;
    }

    auto pattern = patternEntry.getPattern();
    
    llvm::SmallString<16> PatternString;
    PatternBindingPrintLHS(PatternString).visit(pattern);

    // If the bound pattern is a single value, use a DeclRefExpr on the
    // underlying Decl to print it.
    if (auto *NP = dyn_cast<NamedPattern>(pattern->
                                          getSemanticsProvidingPattern())) {
      Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), &SF, PBD->getStartLoc(),
                                       /*Implicit=*/true);
      generatePrintOfExpression(PatternString, E);
      continue;
    }

    // Otherwise, we may not have a way to name all of the pieces of the pattern.
    // Create a repl metavariable to capture the whole thing so we can reference
    // it, then assign that into the pattern.  For example, translate:
    //   var (x, y, _) = foo()
    // into:
    //   var r123 = foo()
    //   var (x, y, _) = r123
    //   replPrint(r123)

    // Remove PBD from the list of Decls so we can insert before it.
    auto PBTLCD = cast<TopLevelCodeDecl>(SF.Decls.back());
    SF.Decls.pop_back();

    // Create the meta-variable, let the typechecker name it.
    Identifier name = TC.getNextResponseVariableName(SF.getParentModule());
    VarDecl *vd = new (Context) VarDecl(/*static*/ false, /*IsLet*/true,
                                        PBD->getStartLoc(), name,
                                        pattern->getType(), &SF);
    SF.Decls.push_back(vd);
    

    // Create a PatternBindingDecl to bind the expression into the decl.
    Pattern *metavarPat = new (Context) NamedPattern(vd);
    metavarPat->setType(vd->getType());
    PatternBindingDecl *metavarBinding
      = PatternBindingDecl::create(Context, SourceLoc(),
                                   StaticSpellingKind::None,
                                   PBD->getStartLoc(), metavarPat,
                                   patternEntry.getInit(), &SF);
    
    auto MVBrace = BraceStmt::create(Context, metavarBinding->getStartLoc(),
                                     ASTNode(metavarBinding),
                                     metavarBinding->getEndLoc());
    
    auto *MVTLCD = new (Context) TopLevelCodeDecl(&SF, MVBrace);
    SF.Decls.push_back(MVTLCD);
    
    
    // Replace the initializer of PBD with a reference to our repl temporary.
    Expr *E = TC.buildCheckedRefExpr(vd, &SF,
                                     vd->getStartLoc(), /*Implicit=*/true);
    E = TC.coerceToMaterializable(E);
    PBD->setInit(entryIdx, E);
    SF.Decls.push_back(PBTLCD);
    
    // Finally, print out the result, by referring to the repl temp.
    E = TC.buildCheckedRefExpr(vd, &SF, vd->getStartLoc(), /*Implicit=*/true);
    generatePrintOfExpression(PatternString, E);
  }
}