428 |
411 |
429 /* ************************************************************************* |
412 /* ************************************************************************* |
430 * Type Checking |
413 * Type Checking |
431 **************************************************************************/ |
414 **************************************************************************/ |
432 |
415 |
|
416 /** |
|
417 * A check context is an object that can be used to perform compatibility |
|
418 * checks - depending on the check context, meaning of 'compatibility' might |
|
419 * vary significantly. |
|
420 */ |
|
421 interface CheckContext { |
|
422 /** |
|
423 * Is type 'found' compatible with type 'req' in given context |
|
424 */ |
|
425 boolean compatible(Type found, Type req, Warner warn); |
|
426 /** |
|
427 * Instantiate a ForAll type against a given target type 'req' in given context |
|
428 */ |
|
429 Type rawInstantiatePoly(ForAll found, Type req, Warner warn); |
|
430 /** |
|
431 * Report a check error |
|
432 */ |
|
433 void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details); |
|
434 /** |
|
435 * Obtain a warner for this check context |
|
436 */ |
|
437 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req); |
|
438 } |
|
439 |
|
440 /** |
|
441 * This class represent a check context that is nested within another check |
|
442 * context - useful to check sub-expressions. The default behavior simply |
|
443 * redirects all method calls to the enclosing check context leveraging |
|
444 * the forwarding pattern. |
|
445 */ |
|
446 static class NestedCheckContext implements CheckContext { |
|
447 CheckContext enclosingContext; |
|
448 |
|
449 NestedCheckContext(CheckContext enclosingContext) { |
|
450 this.enclosingContext = enclosingContext; |
|
451 } |
|
452 |
|
453 public boolean compatible(Type found, Type req, Warner warn) { |
|
454 return enclosingContext.compatible(found, req, warn); |
|
455 } |
|
456 |
|
457 public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) { |
|
458 return enclosingContext.rawInstantiatePoly(found, req, warn); |
|
459 } |
|
460 |
|
461 public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) { |
|
462 enclosingContext.report(pos, found, req, details); |
|
463 } |
|
464 |
|
465 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { |
|
466 return enclosingContext.checkWarner(pos, found, req); |
|
467 } |
|
468 } |
|
469 |
|
470 /** |
|
471 * Check context to be used when evaluating assignment/return statements |
|
472 */ |
|
473 CheckContext basicHandler = new CheckContext() { |
|
474 public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) { |
|
475 if (details == null) { |
|
476 log.error(pos, "prob.found.req", found, req); |
|
477 } else { |
|
478 log.error(pos, "prob.found.req.1", details); |
|
479 } |
|
480 } |
|
481 public boolean compatible(Type found, Type req, Warner warn) { |
|
482 return types.isAssignable(found, req, warn); |
|
483 } |
|
484 |
|
485 public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) { |
|
486 if (req.tag == NONE) |
|
487 req = found.qtype.tag <= VOID ? found.qtype : syms.objectType; |
|
488 return infer.instantiateExpr(found, req, warn); |
|
489 } |
|
490 |
|
491 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { |
|
492 return convertWarner(pos, found, req); |
|
493 } |
|
494 }; |
|
495 |
433 /** Check that a given type is assignable to a given proto-type. |
496 /** Check that a given type is assignable to a given proto-type. |
434 * If it is, return the type, otherwise return errType. |
497 * If it is, return the type, otherwise return errType. |
435 * @param pos Position to be used for error reporting. |
498 * @param pos Position to be used for error reporting. |
436 * @param found The type that was found. |
499 * @param found The type that was found. |
437 * @param req The type that was required. |
500 * @param req The type that was required. |
438 */ |
501 */ |
439 Type checkType(DiagnosticPosition pos, Type found, Type req) { |
502 Type checkType(DiagnosticPosition pos, Type found, Type req) { |
440 return checkType(pos, found, req, "incompatible.types"); |
503 return checkType(pos, found, req, basicHandler); |
441 } |
504 } |
442 |
505 |
443 Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) { |
506 Type checkType(final DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) { |
444 if (req.tag == ERROR) |
507 if (req.tag == ERROR) |
445 return req; |
508 return req; |
446 if (found.tag == FORALL) |
509 if (found.tag == FORALL) { |
447 return instantiatePoly(pos, (ForAll)found, req, convertWarner(pos, found, req)); |
510 ForAll fa = (ForAll)found; |
|
511 Type owntype = instantiatePoly(pos, checkContext, fa, req, checkContext.checkWarner(pos, found, req)); |
|
512 return checkType(pos, owntype, req, checkContext); |
|
513 } |
448 if (req.tag == NONE) |
514 if (req.tag == NONE) |
449 return found; |
515 return found; |
450 if (types.isAssignable(found, req, convertWarner(pos, found, req))) |
516 if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) { |
451 return found; |
517 return found; |
452 if (found.tag <= DOUBLE && req.tag <= DOUBLE) |
518 } else { |
453 return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req); |
519 if (found.tag <= DOUBLE && req.tag <= DOUBLE) { |
454 if (found.isSuperBound()) { |
520 checkContext.report(pos, found, req, diags.fragment("possible.loss.of.precision")); |
455 log.error(pos, "assignment.from.super-bound", found); |
521 return types.createErrorType(found); |
|
522 } |
|
523 checkContext.report(pos, found, req, null); |
456 return types.createErrorType(found); |
524 return types.createErrorType(found); |
457 } |
525 } |
458 if (req.isExtendsBound()) { |
|
459 log.error(pos, "assignment.to.extends-bound", req); |
|
460 return types.createErrorType(found); |
|
461 } |
|
462 return typeError(pos, diags.fragment(errKey), found, req); |
|
463 } |
526 } |
464 |
527 |
465 /** Instantiate polymorphic type to some prototype, unless |
528 /** Instantiate polymorphic type to some prototype, unless |
466 * prototype is `anyPoly' in which case polymorphic type |
529 * prototype is `anyPoly' in which case polymorphic type |
467 * is returned unchanged. |
530 * is returned unchanged. |
468 */ |
531 */ |
469 Type instantiatePoly(DiagnosticPosition pos, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException { |
532 Type instantiatePoly(DiagnosticPosition pos, CheckContext checkContext, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException { |
470 if (pt == Infer.anyPoly && complexInference) { |
533 try { |
471 return t; |
534 return checkContext.rawInstantiatePoly(t, pt, warn); |
472 } else if (pt == Infer.anyPoly || pt.tag == NONE) { |
535 } catch (final Infer.NoInstanceException ex) { |
473 Type newpt = t.qtype.tag <= VOID ? t.qtype : syms.objectType; |
536 JCDiagnostic d = ex.getDiagnostic(); |
474 return instantiatePoly(pos, t, newpt, warn); |
537 if (d != null) { |
475 } else if (pt.tag == ERROR) { |
|
476 return pt; |
|
477 } else { |
|
478 try { |
|
479 return infer.instantiateExpr(t, pt, warn); |
|
480 } catch (Infer.NoInstanceException ex) { |
|
481 if (ex.isAmbiguous) { |
538 if (ex.isAmbiguous) { |
482 JCDiagnostic d = ex.getDiagnostic(); |
539 d = diags.fragment("undetermined.type", t, d); |
483 log.error(pos, |
540 } |
484 "undetermined.type" + (d!=null ? ".1" : ""), |
541 } |
485 t, d); |
542 checkContext.report(pos, t, pt, d); |
486 return types.createErrorType(pt); |
543 return types.createErrorType(pt); |
487 } else { |
544 } catch (Infer.InvalidInstanceException ex) { |
488 JCDiagnostic d = ex.getDiagnostic(); |
545 JCDiagnostic d = ex.getDiagnostic(); |
489 return typeError(pos, |
546 if (d != null) { |
490 diags.fragment("incompatible.types" + (d!=null ? ".1" : ""), d), |
547 d = diags.fragment("invalid.inferred.types", t.tvars, d); |
491 t, pt); |
548 } |
492 } |
549 checkContext.report(pos, t, pt, d); |
493 } catch (Infer.InvalidInstanceException ex) { |
550 return types.createErrorType(pt); |
494 JCDiagnostic d = ex.getDiagnostic(); |
|
495 log.error(pos, "invalid.inferred.types", t.tvars, d); |
|
496 return types.createErrorType(pt); |
|
497 } |
|
498 } |
551 } |
499 } |
552 } |
500 |
553 |
501 /** Check that a given type can be cast to a given target type. |
554 /** Check that a given type can be cast to a given target type. |
502 * Return the result of the cast. |
555 * Return the result of the cast. |
503 * @param pos Position to be used for error reporting. |
556 * @param pos Position to be used for error reporting. |
504 * @param found The type that is being cast. |
557 * @param found The type that is being cast. |
505 * @param req The target type of the cast. |
558 * @param req The target type of the cast. |
506 */ |
559 */ |
507 Type checkCastable(DiagnosticPosition pos, Type found, Type req) { |
560 Type checkCastable(DiagnosticPosition pos, Type found, Type req) { |
|
561 return checkCastable(pos, found, req, basicHandler); |
|
562 } |
|
563 Type checkCastable(DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) { |
508 if (found.tag == FORALL) { |
564 if (found.tag == FORALL) { |
509 instantiatePoly(pos, (ForAll) found, req, castWarner(pos, found, req)); |
565 instantiatePoly(pos, basicHandler, (ForAll) found, req, castWarner(pos, found, req)); |
510 return req; |
566 return req; |
511 } else if (types.isCastable(found, req, castWarner(pos, found, req))) { |
567 } else if (types.isCastable(found, req, castWarner(pos, found, req))) { |
512 return req; |
568 return req; |
513 } else { |
569 } else { |
514 return typeError(pos, |
570 checkContext.report(pos, found, req, diags.fragment("inconvertible.types", found, req)); |
515 diags.fragment("inconvertible.types"), |
571 return types.createErrorType(found); |
516 found, req); |
|
517 } |
572 } |
518 } |
573 } |
519 |
574 |
520 /** Check for redundant casts (i.e. where source type is a subtype of target type) |
575 /** Check for redundant casts (i.e. where source type is a subtype of target type) |
521 * The problem should only be reported for non-292 cast |
576 * The problem should only be reported for non-292 cast |