Skip to content

Commit f2e59cc

Browse files
authored
Auto merge of #34907 - arielb1:found-parse-error, r=nikomatsakis
Centralize and clean type error reporting Refactors the code that handles type errors to be cleaner and fixes various edge cases. This made the already-bad "type mismatch resolving" error message somewhat uglier. I want to fix that in another commit before this PR is merged. Fixes #31173 r? @jonathandturner, cc @nikomatsakis
2 parents 29abe5e + 717e392 commit f2e59cc

File tree

85 files changed

+1017
-844
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1017
-844
lines changed

src/librustc/infer/error_reporting.rs

+93-143
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ use hir::def_id::DefId;
8383
use infer::{self, TypeOrigin};
8484
use middle::region;
8585
use ty::subst;
86-
use ty::{self, Ty, TyCtxt, TypeFoldable};
86+
use ty::{self, TyCtxt, TypeFoldable};
8787
use ty::{Region, ReFree};
8888
use ty::error::TypeError;
8989

@@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
462462
}
463463
}
464464

465-
fn report_type_error(&self,
466-
trace: TypeTrace<'tcx>,
467-
terr: &TypeError<'tcx>)
468-
-> DiagnosticBuilder<'tcx> {
469-
let (expected, found) = match self.values_str(&trace.values) {
470-
Some(v) => v,
471-
None => {
472-
return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
473-
}
474-
};
475-
476-
let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
477-
values.expected.is_primitive() && values.found.is_primitive()
478-
} else {
479-
false
480-
};
481-
482-
let mut err = struct_span_err!(self.tcx.sess,
483-
trace.origin.span(),
484-
E0308,
485-
"{}",
486-
trace.origin);
487-
488-
if !is_simple_error || check_old_school() {
489-
err.note_expected_found(&"type", &expected, &found);
490-
}
491-
492-
err.span_label(trace.origin.span(), &terr);
493-
494-
self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
495-
496-
match trace.origin {
497-
TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
498-
hir::MatchSource::IfLetDesugar{..} => {
499-
err.span_note(arm_span, "`if let` arm with an incompatible type");
500-
}
501-
_ => {
502-
err.span_note(arm_span, "match arm with an incompatible type");
503-
}
504-
},
505-
_ => ()
506-
}
507-
508-
err
509-
}
510-
511465
/// Adds a note if the types come from similarly named crates
512466
fn check_and_note_conflicting_crates(&self,
513467
err: &mut DiagnosticBuilder,
@@ -550,42 +504,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
550504
}
551505
}
552506

507+
fn note_error_origin(&self,
508+
err: &mut DiagnosticBuilder<'tcx>,
509+
origin: &TypeOrigin)
510+
{
511+
match origin {
512+
&TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
513+
hir::MatchSource::IfLetDesugar {..} => {
514+
err.span_note(arm_span, "`if let` arm with an incompatible type");
515+
}
516+
_ => {
517+
err.span_note(arm_span, "match arm with an incompatible type");
518+
}
519+
},
520+
_ => ()
521+
}
522+
}
523+
524+
pub fn note_type_err(&self,
525+
diag: &mut DiagnosticBuilder<'tcx>,
526+
origin: TypeOrigin,
527+
values: Option<ValuePairs<'tcx>>,
528+
terr: &TypeError<'tcx>)
529+
{
530+
let expected_found = match values {
531+
None => None,
532+
Some(values) => match self.values_str(&values) {
533+
Some((expected, found)) => Some((expected, found)),
534+
None => {
535+
// Derived error. Cancel the emitter.
536+
self.tcx.sess.diagnostic().cancel(diag);
537+
return
538+
}
539+
}
540+
};
541+
542+
let span = origin.span();
543+
544+
let mut is_simple_error = false;
545+
546+
if let Some((expected, found)) = expected_found {
547+
is_simple_error = if let &TypeError::Sorts(ref values) = terr {
548+
values.expected.is_primitive() && values.found.is_primitive()
549+
} else {
550+
false
551+
};
552+
553+
if !is_simple_error || check_old_school() {
554+
diag.note_expected_found(&"type", &expected, &found);
555+
}
556+
}
557+
558+
if !is_simple_error && check_old_school() {
559+
diag.span_note(span, &format!("{}", terr));
560+
} else {
561+
diag.span_label(span, &terr);
562+
}
563+
564+
self.note_error_origin(diag, &origin);
565+
self.check_and_note_conflicting_crates(diag, terr, span);
566+
self.tcx.note_and_explain_type_err(diag, terr, span);
567+
}
568+
553569
pub fn report_and_explain_type_error(&self,
554570
trace: TypeTrace<'tcx>,
555571
terr: &TypeError<'tcx>)
556-
-> DiagnosticBuilder<'tcx> {
557-
let span = trace.origin.span();
558-
let mut err = self.report_type_error(trace, terr);
559-
self.tcx.note_and_explain_type_err(&mut err, terr, span);
560-
err
572+
-> DiagnosticBuilder<'tcx>
573+
{
574+
// FIXME: do we want to use a different error code for each origin?
575+
let mut diag = struct_span_err!(
576+
self.tcx.sess, trace.origin.span(), E0308,
577+
"{}", trace.origin.as_failure_str()
578+
);
579+
self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
580+
diag
561581
}
562582

563-
/// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
564-
/// error.
583+
/// Returns a string of the form "expected `{}`, found `{}`".
565584
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
566585
match *values {
567586
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
568587
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
569-
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
588+
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
570589
}
571590
}
572591

573-
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
592+
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
574593
&self,
575594
exp_found: &ty::error::ExpectedFound<T>)
576595
-> Option<(String, String)>
577596
{
578-
let expected = exp_found.expected.resolve(self);
579-
if expected.references_error() {
580-
return None;
581-
}
582-
583-
let found = exp_found.found.resolve(self);
584-
if found.references_error() {
597+
let exp_found = self.resolve_type_vars_if_possible(exp_found);
598+
if exp_found.references_error() {
585599
return None;
586600
}
587601

588-
Some((format!("{}", expected), format!("{}", found)))
602+
Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
589603
}
590604

591605
fn report_generic_bound_failure(&self,
@@ -1608,59 +1622,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
16081622
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
16091623
match *origin {
16101624
infer::Subtype(ref trace) => {
1611-
let desc = match trace.origin {
1612-
TypeOrigin::Misc(_) => {
1613-
"types are compatible"
1614-
}
1615-
TypeOrigin::MethodCompatCheck(_) => {
1616-
"method type is compatible with trait"
1617-
}
1618-
TypeOrigin::ExprAssignable(_) => {
1619-
"expression is assignable"
1620-
}
1621-
TypeOrigin::RelateTraitRefs(_) => {
1622-
"traits are compatible"
1623-
}
1624-
TypeOrigin::RelateSelfType(_) => {
1625-
"self type matches impl self type"
1626-
}
1627-
TypeOrigin::RelateOutputImplTypes(_) => {
1628-
"trait type parameters matches those \
1629-
specified on the impl"
1630-
}
1631-
TypeOrigin::MatchExpressionArm(_, _, _) => {
1632-
"match arms have compatible types"
1633-
}
1634-
TypeOrigin::IfExpression(_) => {
1635-
"if and else have compatible types"
1636-
}
1637-
TypeOrigin::IfExpressionWithNoElse(_) => {
1638-
"if may be missing an else clause"
1639-
}
1640-
TypeOrigin::RangeExpression(_) => {
1641-
"start and end of range have compatible types"
1642-
}
1643-
TypeOrigin::EquatePredicate(_) => {
1644-
"equality where clause is satisfied"
1645-
}
1646-
};
1647-
1648-
match self.values_str(&trace.values) {
1649-
Some((expected, found)) => {
1650-
err.span_note(
1651-
trace.origin.span(),
1652-
&format!("...so that {} (expected {}, found {})",
1653-
desc, expected, found));
1654-
}
1655-
None => {
1656-
// Really should avoid printing this error at
1657-
// all, since it is derived, but that would
1658-
// require more refactoring than I feel like
1659-
// doing right now. - nmatsakis
1660-
err.span_note(
1661-
trace.origin.span(),
1662-
&format!("...so that {}", desc));
1663-
}
1625+
if let Some((expected, found)) = self.values_str(&trace.values) {
1626+
// FIXME: do we want a "the" here?
1627+
err.span_note(
1628+
trace.origin.span(),
1629+
&format!("...so that {} (expected {}, found {})",
1630+
trace.origin.as_requirement_str(), expected, found));
1631+
} else {
1632+
// FIXME: this really should be handled at some earlier stage. Our
1633+
// handling of region checking when type errors are present is
1634+
// *terrible*.
1635+
1636+
err.span_note(
1637+
trace.origin.span(),
1638+
&format!("...so that {}",
1639+
trace.origin.as_requirement_str()));
16641640
}
16651641
}
16661642
infer::Reborrow(span) => {
@@ -1803,32 +1779,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
18031779
}
18041780
}
18051781

1806-
pub trait Resolvable<'tcx> {
1807-
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
1808-
}
1809-
1810-
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
1811-
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
1812-
infcx.resolve_type_vars_if_possible(self)
1813-
}
1814-
}
1815-
1816-
impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
1817-
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
1818-
-> ty::TraitRef<'tcx> {
1819-
infcx.resolve_type_vars_if_possible(self)
1820-
}
1821-
}
1822-
1823-
impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
1824-
fn resolve<'a, 'gcx>(&self,
1825-
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
1826-
-> ty::PolyTraitRef<'tcx>
1827-
{
1828-
infcx.resolve_type_vars_if_possible(self)
1829-
}
1830-
}
1831-
18321782
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
18331783
scope_id: ast::NodeId)
18341784
-> Vec<hir::LifetimeDef> {

0 commit comments

Comments
 (0)