mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #33596 - nikomatsakis:issue-33586-regr-assoc-type-path, r=eddyb
re-introduce a cache for ast-ty-to-ty It turns out that `ast_ty_to_ty` is supposed to be updating the `def` after it finishes, but at some point in the past it stopped doing so. This was never noticed because of the `ast_ty_to_ty_cache`, but that cache was recently removed. This PR fixes the code to update the def properly, but apparently that is not quite enough to make the operation idempotent, so for now we reintroduce the cache too. Fixes #33586. r? @eddyb
This commit is contained in:
commit
709e5c5fde
@ -2544,6 +2544,8 @@ impl<'a> Resolver<'a> {
|
||||
/// returned value. See `hir::def::PathResolution` for more info.
|
||||
fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace)
|
||||
-> Result<PathResolution, bool /* true if an error was reported */ > {
|
||||
debug!("resolve_path(id={:?} path={:?}, path_depth={:?})", id, path, path_depth);
|
||||
|
||||
let span = path.span;
|
||||
let segments = &path.segments[..path.segments.len() - path_depth];
|
||||
|
||||
|
@ -64,10 +64,10 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
|
||||
ElisionFailureInfo, ElidedLifetime};
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
use util::nodemap::FnvHashSet;
|
||||
use util::nodemap::{NodeMap, FnvHashSet};
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use syntax::{abi, ast};
|
||||
use syntax::codemap::{Span, Pos};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
@ -81,6 +81,9 @@ use rustc_back::slice;
|
||||
pub trait AstConv<'gcx, 'tcx> {
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
|
||||
|
||||
/// A cache used for the result of `ast_ty_to_ty_cache`
|
||||
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
|
||||
|
||||
/// Identify the type scheme for an item with a type, like a type
|
||||
/// alias, fn, or struct. This allows you to figure out the set of
|
||||
/// type parameters defined on the item.
|
||||
@ -1416,13 +1419,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
param_mode: PathParamMode,
|
||||
def: &Def,
|
||||
def: Def,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
base_segments: &[hir::PathSegment])
|
||||
-> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
match *def {
|
||||
debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, base_segments={:?})",
|
||||
def, opt_self_ty, base_segments);
|
||||
|
||||
match def {
|
||||
Def::Trait(trait_def_id) => {
|
||||
// N.B. this case overlaps somewhat with
|
||||
// TyObjectSum, see that fn for details
|
||||
@ -1515,20 +1521,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
param_mode: PathParamMode,
|
||||
def: &Def,
|
||||
mut def: Def,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
base_segments: &[hir::PathSegment],
|
||||
assoc_segments: &[hir::PathSegment])
|
||||
-> Ty<'tcx> {
|
||||
-> (Ty<'tcx>, Def) {
|
||||
debug!("finish_resolving_def_to_ty(def={:?}, \
|
||||
base_segments={:?}, \
|
||||
assoc_segments={:?})",
|
||||
def,
|
||||
base_segments,
|
||||
assoc_segments);
|
||||
let mut ty = self.base_def_to_ty(rscope,
|
||||
span,
|
||||
param_mode,
|
||||
def,
|
||||
opt_self_ty,
|
||||
base_segments);
|
||||
let mut def = *def;
|
||||
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
|
||||
// If any associated type segments remain, attempt to resolve them.
|
||||
for segment in assoc_segments {
|
||||
debug!("finish_resolving_def_to_ty: segment={:?}", segment);
|
||||
if ty.sty == ty::TyError {
|
||||
break;
|
||||
}
|
||||
@ -1540,7 +1553,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
ty = a_ty;
|
||||
def = a_def;
|
||||
}
|
||||
ty
|
||||
(ty, def)
|
||||
}
|
||||
|
||||
/// Parses the programmer's textual representation of a type into our
|
||||
@ -1551,7 +1564,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
|
||||
let tcx = self.tcx();
|
||||
|
||||
match ast_ty.node {
|
||||
let cache = self.ast_ty_to_ty_cache();
|
||||
match cache.borrow().get(&ast_ty.id) {
|
||||
Some(ty) => { return ty; }
|
||||
None => { }
|
||||
}
|
||||
|
||||
let result_ty = match ast_ty.node {
|
||||
hir::TyVec(ref ty) => {
|
||||
tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty))
|
||||
}
|
||||
@ -1599,6 +1618,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
|
||||
}
|
||||
hir::TyPath(ref maybe_qself, ref path) => {
|
||||
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
|
||||
let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
|
||||
d
|
||||
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
|
||||
@ -1615,13 +1635,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
|
||||
self.ast_ty_to_ty(rscope, &qself.ty)
|
||||
});
|
||||
let ty = self.finish_resolving_def_to_ty(rscope,
|
||||
ast_ty.span,
|
||||
PathParamMode::Explicit,
|
||||
&def,
|
||||
opt_self_ty,
|
||||
&path.segments[..base_ty_end],
|
||||
&path.segments[base_ty_end..]);
|
||||
let (ty, _def) = self.finish_resolving_def_to_ty(rscope,
|
||||
ast_ty.span,
|
||||
PathParamMode::Explicit,
|
||||
def,
|
||||
opt_self_ty,
|
||||
&path.segments[..base_ty_end],
|
||||
&path.segments[base_ty_end..]);
|
||||
|
||||
if path_res.depth != 0 && ty.sty != ty::TyError {
|
||||
// Write back the new resolution.
|
||||
@ -1675,7 +1695,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
// handled specially and will not descend into this routine.
|
||||
self.ty_infer(None, None, None, ast_ty.span)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cache.borrow_mut().insert(ast_ty.id, result_ty);
|
||||
|
||||
result_ty
|
||||
}
|
||||
|
||||
pub fn ty_of_arg(&self,
|
||||
|
@ -346,6 +346,8 @@ impl UnsafetyState {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
|
||||
|
||||
body_id: ast::NodeId,
|
||||
|
||||
// This flag is set to true if, during the writeback phase, we encounter
|
||||
@ -1262,6 +1264,10 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
|
||||
|
||||
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> {
|
||||
&self.ast_ty_to_ty_cache
|
||||
}
|
||||
|
||||
fn get_item_type_scheme(&self, _: Span, id: DefId)
|
||||
-> Result<ty::TypeScheme<'tcx>, ErrorReported>
|
||||
{
|
||||
@ -1434,6 +1440,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
body_id: ast::NodeId)
|
||||
-> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
FnCtxt {
|
||||
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
||||
body_id: body_id,
|
||||
writeback_errors: Cell::new(false),
|
||||
err_count_on_creation: inh.tcx.sess.err_count(),
|
||||
@ -3845,15 +3852,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
if path_res.depth == 0 {
|
||||
Some((opt_self_ty, &path.segments, path_res.base_def))
|
||||
} else {
|
||||
let mut def = path_res.base_def;
|
||||
let def = path_res.base_def;
|
||||
let ty_segments = path.segments.split_last().unwrap().1;
|
||||
let base_ty_end = path.segments.len() - path_res.depth;
|
||||
let ty = AstConv::finish_resolving_def_to_ty(self, self, span,
|
||||
PathParamMode::Optional,
|
||||
&mut def,
|
||||
opt_self_ty,
|
||||
&ty_segments[..base_ty_end],
|
||||
&ty_segments[base_ty_end..]);
|
||||
let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span,
|
||||
PathParamMode::Optional,
|
||||
def,
|
||||
opt_self_ty,
|
||||
&ty_segments[..base_ty_end],
|
||||
&ty_segments[base_ty_end..]);
|
||||
let item_segment = path.segments.last().unwrap();
|
||||
let item_name = item_segment.identifier.name;
|
||||
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
|
||||
|
@ -78,11 +78,12 @@ use rscope::*;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir::map as hir_map;
|
||||
use util::common::{ErrorReported, MemoizationMap};
|
||||
use util::nodemap::FnvHashMap;
|
||||
use util::nodemap::{NodeMap, FnvHashMap};
|
||||
use {CrateCtxt, write_ty_to_tcx};
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::rc::Rc;
|
||||
@ -146,7 +147,10 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx>
|
||||
|
||||
impl<'a,'tcx> CrateCtxt<'a,'tcx> {
|
||||
fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> {
|
||||
ItemCtxt { ccx: self, param_bounds: param_bounds }
|
||||
ItemCtxt {
|
||||
ccx: self,
|
||||
param_bounds: param_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn cycle_check<F,R>(&self,
|
||||
@ -298,6 +302,10 @@ impl<'a,'tcx> ItemCtxt<'a,'tcx> {
|
||||
impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.ccx.tcx }
|
||||
|
||||
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> {
|
||||
&self.ccx.ast_ty_to_ty_cache
|
||||
}
|
||||
|
||||
fn get_item_type_scheme(&self, span: Span, id: DefId)
|
||||
-> Result<ty::TypeScheme<'tcx>, ErrorReported>
|
||||
{
|
||||
|
@ -116,6 +116,7 @@ use syntax::ast;
|
||||
use syntax::abi::Abi;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
// registered before they are used.
|
||||
@ -136,7 +137,9 @@ pub struct TypeAndSubsts<'tcx> {
|
||||
}
|
||||
|
||||
pub struct CrateCtxt<'a, 'tcx: 'a> {
|
||||
// A mapping from method call sites to traits that have that method.
|
||||
ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
|
||||
|
||||
/// A mapping from method call sites to traits that have that method.
|
||||
pub trait_map: hir::TraitMap,
|
||||
|
||||
/// A vector of every trait accessible in the whole crate
|
||||
@ -334,6 +337,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
-> CompileResult {
|
||||
let time_passes = tcx.sess.time_passes();
|
||||
let ccx = CrateCtxt {
|
||||
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
||||
trait_map: trait_map,
|
||||
all_traits: RefCell::new(None),
|
||||
stack: RefCell::new(Vec::new()),
|
||||
|
26
src/test/run-pass/associated-types-in-bound-type-arg.rs
Normal file
26
src/test/run-pass/associated-types-in-bound-type-arg.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test the case where we resolve `C::Result` and the trait bound
|
||||
// itself includes a `Self::Item` shorthand.
|
||||
//
|
||||
// Regression test for issue #33425.
|
||||
|
||||
trait ParallelIterator {
|
||||
type Item;
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where C: Consumer<Self::Item>;
|
||||
}
|
||||
|
||||
pub trait Consumer<ITEM> {
|
||||
type Result;
|
||||
}
|
||||
|
||||
fn main() { }
|
Loading…
Reference in New Issue
Block a user