Skip to content

Commit 8a09bc6

Browse files
committed
Auto merge of #48995 - aravind-pg:canonical-query, r=nikomatsakis
Create a canonical trait query for `evaluate_obligation` This builds on the canonical query machinery introduced in #48411 to introduce a new canonical trait query for `evaluate_obligation` in the trait selector. Also ports most callers of the original `evaluate_obligation` to the new system (except in coherence, which requires support for intercrate mode). Closes #48537. r? @nikomatsakis
2 parents e05b78d + e423dcc commit 8a09bc6

File tree

21 files changed

+341
-109
lines changed

21 files changed

+341
-109
lines changed

Diff for: src/librustc/dep_graph/dep_node.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
7070
use std::fmt;
7171
use std::hash::Hash;
7272
use syntax_pos::symbol::InternedString;
73-
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
73+
use traits::query::{CanonicalProjectionGoal,
74+
CanonicalTyGoal, CanonicalPredicateGoal};
7475
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
7576
use ty::subst::Substs;
7677

@@ -643,6 +644,7 @@ define_dep_nodes!( <'tcx>
643644
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
644645
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
645646
[] DropckOutlives(CanonicalTyGoal<'tcx>),
647+
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
646648

647649
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
648650

Diff for: src/librustc/traits/coherence.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
154154
recursion_depth: 0,
155155
predicate: p })
156156
.chain(obligations)
157-
.find(|o| !selcx.evaluate_obligation(o));
157+
.find(|o| !selcx.predicate_may_hold_fatal(o));
158+
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
159+
// to the canonical trait query form, `infcx.predicate_may_hold`, once
160+
// the new system supports intercrate mode (which coherence needs).
158161

159162
if let Some(failing_obligation) = opt_failing_obligation {
160163
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);

Diff for: src/librustc/traits/error_reporting.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use super::{
2424
SelectionContext,
2525
SelectionError,
2626
ObjectSafetyViolation,
27+
Overflow,
2728
};
2829

2930
use errors::DiagnosticBuilder;
@@ -659,8 +660,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
659660
predicate: ty::Predicate::Trait(predicate),
660661
.. obligation.clone()
661662
};
662-
let mut selcx = SelectionContext::new(self);
663-
if selcx.evaluate_obligation(&unit_obligation) {
663+
if self.predicate_may_hold(&unit_obligation) {
664664
err.note("the trait is implemented for `()`. \
665665
Possibly this error has been caused by changes to \
666666
Rust's type-inference algorithm \
@@ -830,6 +830,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
830830
}
831831
err.struct_error(self.tcx, span, "constant expression")
832832
}
833+
834+
Overflow => {
835+
bug!("overflow should be handled before the `report_selection_error` path");
836+
}
833837
};
834838
self.note_obligation_cause(&mut err, obligation);
835839
err.emit();
@@ -872,7 +876,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
872876
.count();
873877

874878
let mut trait_type = trait_ref.self_ty();
875-
let mut selcx = SelectionContext::new(self);
876879

877880
for refs_remaining in 0..refs_number {
878881
if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) =
@@ -886,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
886889
obligation.param_env,
887890
new_trait_ref.to_predicate());
888891

889-
if selcx.evaluate_obligation(&new_obligation) {
892+
if self.predicate_may_hold(&new_obligation) {
890893
let sp = self.tcx.sess.codemap()
891894
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
892895

@@ -1322,7 +1325,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
13221325
cleaned_pred.to_predicate()
13231326
);
13241327

1325-
selcx.evaluate_obligation(&obligation)
1328+
self.predicate_may_hold(&obligation)
13261329
})
13271330
}
13281331

Diff for: src/librustc/traits/fulfill.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
333333
if data.is_global() {
334334
// no type variables present, can use evaluation for better caching.
335335
// FIXME: consider caching errors too.
336-
if selcx.evaluate_obligation_conservatively(&obligation) {
336+
if selcx.infcx().predicate_must_hold(&obligation) {
337337
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
338338
data, obligation.recursion_depth);
339339
return Ok(Some(vec![]))

Diff for: src/librustc/traits/mod.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub use self::object_safety::ObjectSafetyViolation;
4141
pub use self::object_safety::MethodViolationCode;
4242
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
4343
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
44-
pub use self::select::IntercrateAmbiguityCause;
44+
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
4545
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
4646
pub use self::specialize::{SpecializesCache, find_associated_item};
4747
pub use self::engine::TraitEngine;
@@ -74,6 +74,19 @@ pub enum IntercrateMode {
7474
Fixed
7575
}
7676

77+
// The mode that trait queries run in
78+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
79+
pub enum TraitQueryMode {
80+
// Standard/un-canonicalized queries get accurate
81+
// spans etc. passed in and hence can do reasonable
82+
// error reporting on their own.
83+
Standard,
84+
// Canonicalized queries get dummy spans and hence
85+
// must generally propagate errors to
86+
// pre-canonicalization callsites.
87+
Canonical,
88+
}
89+
7790
/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
7891
/// which the vtable must be found. The process of finding a vtable is
7992
/// called "resolving" the `Obligation`. This process consists of
@@ -349,6 +362,7 @@ pub enum SelectionError<'tcx> {
349362
ty::error::TypeError<'tcx>),
350363
TraitNotObjectSafe(DefId),
351364
ConstEvalFailure(ConstEvalErr<'tcx>),
365+
Overflow,
352366
}
353367

354368
pub struct FulfillmentError<'tcx> {
@@ -550,8 +564,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
550564
predicate: trait_ref.to_predicate(),
551565
};
552566

553-
let result = SelectionContext::new(infcx)
554-
.evaluate_obligation_conservatively(&obligation);
567+
let result = infcx.predicate_must_hold(&obligation);
555568
debug!("type_known_to_meet_ty={:?} bound={} => {:?}",
556569
ty, infcx.tcx.item_path_str(def_id), result);
557570

Diff for: src/librustc/traits/query/evaluate_obligation.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use infer::InferCtxt;
12+
use infer::canonical::{Canonical, Canonicalize};
13+
use traits::{EvaluationResult, PredicateObligation, SelectionContext,
14+
TraitQueryMode, OverflowError};
15+
use traits::query::CanonicalPredicateGoal;
16+
use ty::{ParamEnvAnd, Predicate, TyCtxt};
17+
18+
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
19+
/// Evaluates whether the predicate can be satisfied (by any means)
20+
/// in the given `ParamEnv`.
21+
pub fn predicate_may_hold(
22+
&self,
23+
obligation: &PredicateObligation<'tcx>,
24+
) -> bool {
25+
self.evaluate_obligation(obligation).may_apply()
26+
}
27+
28+
/// Evaluates whether the predicate can be satisfied in the given
29+
/// `ParamEnv`, and returns `false` if not certain. However, this is
30+
/// not entirely accurate if inference variables are involved.
31+
pub fn predicate_must_hold(
32+
&self,
33+
obligation: &PredicateObligation<'tcx>,
34+
) -> bool {
35+
self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk
36+
}
37+
38+
// Helper function that canonicalizes and runs the query, as well as handles
39+
// overflow.
40+
fn evaluate_obligation(
41+
&self,
42+
obligation: &PredicateObligation<'tcx>,
43+
) -> EvaluationResult {
44+
let (c_pred, _) =
45+
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
46+
// Run canonical query. If overflow occurs, rerun from scratch but this time
47+
// in standard trait query mode so that overflow is handled appropriately
48+
// within `SelectionContext`.
49+
match self.tcx.global_tcx().evaluate_obligation(c_pred) {
50+
Ok(result) => result,
51+
Err(OverflowError) => {
52+
let mut selcx =
53+
SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
54+
selcx.evaluate_obligation_recursively(obligation)
55+
.expect("Overflow should be caught earlier in standard query mode")
56+
}
57+
}
58+
}
59+
}
60+
61+
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> {
62+
type Canonicalized = CanonicalPredicateGoal<'gcx>;
63+
64+
fn intern(
65+
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
66+
value: Canonical<'gcx, Self::Lifted>,
67+
) -> Self::Canonicalized {
68+
value
69+
}
70+
}

Diff for: src/librustc/traits/query/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use infer::canonical::Canonical;
1919
use ty::{self, Ty};
2020

2121
pub mod dropck_outlives;
22+
pub mod evaluate_obligation;
2223
pub mod normalize;
2324
pub mod normalize_erasing_regions;
2425

@@ -27,6 +28,9 @@ pub type CanonicalProjectionGoal<'tcx> =
2728

2829
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
2930

31+
pub type CanonicalPredicateGoal<'tcx> =
32+
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
33+
3034
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
3135
pub struct NoSolution;
3236

0 commit comments

Comments
 (0)