Auto merge of #22512 - nikomatsakis:issue-20300-where-clause-not-bounds, r=nikomatsakis
This is a fix for #20300 though as a side-sweep it fixes a number of stack overflows because it integrates cycle detection into the conversion process. I didn't go through and retest everything. The tricky part here is that in some cases we have to go find the information we need from the AST -- we can't use the converted form of the where-clauses because we often have to handle something like `T::Item` *while converting the where-clauses themselves*. Since this is also not a fixed-point process we can't just try and keep trying to find the best order. So instead I modified the `AstConv` interface to allow you to request the bounds for a type parameter; we'll then do a secondary scan of the where-clauses to figure out what we need. This may create a cycle in some cases, but we have code to catch that. Another approach that is NOT taken by this PR would be to "convert" `T::Item` into a form that does not specify what trait it's using. This then kind of defers the problem of picking the trait till later. That might be a good idea, but it would make normalization and everything else much harder, so I'm holding off on that (and hoping to find a better way for handling things like `i32::T`). This PR also removes "most of" the `bounds` struct from `TypeParameterDef`. Still a little ways to go before `ParamBounds` can be removed entirely -- it's used for supertraits, for example (though those really ought to be converted, I think, to a call to `get_type_parameter_bounds` on `Self` from within the trait definition). cc @jroesch Fixes #20300
This commit is contained in:
commit
880fb89bde
18 changed files with 1071 additions and 422 deletions
|
@ -822,7 +822,6 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||||
assert_eq!(next(st), '|');
|
assert_eq!(next(st), '|');
|
||||||
let index = parse_u32(st);
|
let index = parse_u32(st);
|
||||||
assert_eq!(next(st), '|');
|
assert_eq!(next(st), '|');
|
||||||
let bounds = parse_bounds_(st, conv);
|
|
||||||
let default = parse_opt(st, |st| parse_ty_(st, conv));
|
let default = parse_opt(st, |st| parse_ty_(st, conv));
|
||||||
let object_lifetime_default = parse_object_lifetime_default(st, conv);
|
let object_lifetime_default = parse_object_lifetime_default(st, conv);
|
||||||
|
|
||||||
|
@ -831,7 +830,6 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||||
def_id: def_id,
|
def_id: def_id,
|
||||||
space: space,
|
space: space,
|
||||||
index: index,
|
index: index,
|
||||||
bounds: bounds,
|
|
||||||
default: default,
|
default: default,
|
||||||
object_lifetime_default: object_lifetime_default,
|
object_lifetime_default: object_lifetime_default,
|
||||||
}
|
}
|
||||||
|
@ -924,18 +922,18 @@ fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||||
{
|
{
|
||||||
let builtin_bounds = parse_builtin_bounds_(st, conv);
|
let builtin_bounds = parse_builtin_bounds_(st, conv);
|
||||||
|
|
||||||
|
let region_bounds = parse_region_bounds_(st, conv);
|
||||||
|
|
||||||
let mut param_bounds = ty::ParamBounds {
|
let mut param_bounds = ty::ParamBounds {
|
||||||
region_bounds: Vec::new(),
|
region_bounds: region_bounds,
|
||||||
builtin_bounds: builtin_bounds,
|
builtin_bounds: builtin_bounds,
|
||||||
trait_bounds: Vec::new(),
|
trait_bounds: Vec::new(),
|
||||||
projection_bounds: Vec::new(),
|
projection_bounds: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match next(st) {
|
match next(st) {
|
||||||
'R' => {
|
|
||||||
param_bounds.region_bounds.push(
|
|
||||||
parse_region_(st, conv));
|
|
||||||
}
|
|
||||||
'I' => {
|
'I' => {
|
||||||
param_bounds.trait_bounds.push(
|
param_bounds.trait_bounds.push(
|
||||||
ty::Binder(parse_trait_ref_(st, conv)));
|
ty::Binder(parse_trait_ref_(st, conv)));
|
||||||
|
@ -953,3 +951,18 @@ fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_region_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||||
|
-> Vec<ty::Region> where
|
||||||
|
F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
|
||||||
|
{
|
||||||
|
let mut region_bounds = Vec::new();
|
||||||
|
loop {
|
||||||
|
match next(st) {
|
||||||
|
'R' => { region_bounds.push(parse_region_(st, conv)); }
|
||||||
|
'.' => { return region_bounds; }
|
||||||
|
c => { panic!("parse_bounds: bad bounds ('{}')", c); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,10 +386,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
|
||||||
bs: &ty::ParamBounds<'tcx>) {
|
bs: &ty::ParamBounds<'tcx>) {
|
||||||
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
|
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
|
||||||
|
|
||||||
for &r in &bs.region_bounds {
|
enc_region_bounds(w, cx, &bs.region_bounds);
|
||||||
mywrite!(w, "R");
|
|
||||||
enc_region(w, cx, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
for tp in &bs.trait_bounds {
|
for tp in &bs.trait_bounds {
|
||||||
mywrite!(w, "I");
|
mywrite!(w, "I");
|
||||||
|
@ -404,12 +401,22 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
|
||||||
mywrite!(w, ".");
|
mywrite!(w, ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enc_region_bounds<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||||
|
cx: &ctxt<'a, 'tcx>,
|
||||||
|
rs: &[ty::Region]) {
|
||||||
|
for &r in rs {
|
||||||
|
mywrite!(w, "R");
|
||||||
|
enc_region(w, cx, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
mywrite!(w, ".");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
|
pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
|
||||||
v: &ty::TypeParameterDef<'tcx>) {
|
v: &ty::TypeParameterDef<'tcx>) {
|
||||||
mywrite!(w, "{}:{}|{}|{}|",
|
mywrite!(w, "{}:{}|{}|{}|",
|
||||||
token::get_name(v.name), (cx.ds)(v.def_id),
|
token::get_name(v.name), (cx.ds)(v.def_id),
|
||||||
v.space.to_uint(), v.index);
|
v.space.to_uint(), v.index);
|
||||||
enc_bounds(w, cx, &v.bounds);
|
|
||||||
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||||
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
|
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ use middle::region;
|
||||||
use middle::resolve_lifetime;
|
use middle::resolve_lifetime;
|
||||||
use middle::infer;
|
use middle::infer;
|
||||||
use middle::stability;
|
use middle::stability;
|
||||||
use middle::subst::{self, Subst, Substs, VecPerParamSpace};
|
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
|
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
|
||||||
|
@ -1750,7 +1750,6 @@ pub struct TypeParameterDef<'tcx> {
|
||||||
pub def_id: ast::DefId,
|
pub def_id: ast::DefId,
|
||||||
pub space: subst::ParamSpace,
|
pub space: subst::ParamSpace,
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub bounds: ParamBounds<'tcx>,
|
|
||||||
pub default: Option<Ty<'tcx>>,
|
pub default: Option<Ty<'tcx>>,
|
||||||
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
|
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
|
||||||
}
|
}
|
||||||
|
@ -2546,6 +2545,13 @@ impl<'tcx> ctxt<'tcx> {
|
||||||
{
|
{
|
||||||
self.closure_tys.borrow()[def_id].subst(self, substs)
|
self.closure_tys.borrow()[def_id].subst(self, substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_parameter_def(&self,
|
||||||
|
node_id: ast::NodeId)
|
||||||
|
-> TypeParameterDef<'tcx>
|
||||||
|
{
|
||||||
|
self.ty_param_defs.borrow()[node_id].clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interns a type/name combination, stores the resulting box in cx.interner,
|
// Interns a type/name combination, stores the resulting box in cx.interner,
|
||||||
|
@ -2996,6 +3002,13 @@ impl<'tcx> TyS<'tcx> {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
|
||||||
|
match self.sty {
|
||||||
|
ty::ty_param(ref data) => data.space == space && data.idx == index,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F)
|
pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F)
|
||||||
|
|
|
@ -377,7 +377,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
|
||||||
def_id: self.def_id,
|
def_id: self.def_id,
|
||||||
space: self.space,
|
space: self.space,
|
||||||
index: self.index,
|
index: self.index,
|
||||||
bounds: self.bounds.fold_with(folder),
|
|
||||||
default: self.default.fold_with(folder),
|
default: self.default.fold_with(folder),
|
||||||
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
|
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ pub struct Options {
|
||||||
pub test: bool,
|
pub test: bool,
|
||||||
pub parse_only: bool,
|
pub parse_only: bool,
|
||||||
pub no_trans: bool,
|
pub no_trans: bool,
|
||||||
|
pub treat_err_as_bug: bool,
|
||||||
pub no_analysis: bool,
|
pub no_analysis: bool,
|
||||||
pub debugging_opts: DebuggingOptions,
|
pub debugging_opts: DebuggingOptions,
|
||||||
/// Whether to write dependency files. It's (enabled, optional filename).
|
/// Whether to write dependency files. It's (enabled, optional filename).
|
||||||
|
@ -223,6 +224,7 @@ pub fn basic_options() -> Options {
|
||||||
test: false,
|
test: false,
|
||||||
parse_only: false,
|
parse_only: false,
|
||||||
no_trans: false,
|
no_trans: false,
|
||||||
|
treat_err_as_bug: false,
|
||||||
no_analysis: false,
|
no_analysis: false,
|
||||||
debugging_opts: basic_debugging_options(),
|
debugging_opts: basic_debugging_options(),
|
||||||
write_dependency_info: (false, None),
|
write_dependency_info: (false, None),
|
||||||
|
@ -573,6 +575,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||||
"Parse only; do not compile, assemble, or link"),
|
"Parse only; do not compile, assemble, or link"),
|
||||||
no_trans: bool = (false, parse_bool,
|
no_trans: bool = (false, parse_bool,
|
||||||
"Run all passes except translation; no output"),
|
"Run all passes except translation; no output"),
|
||||||
|
treat_err_as_bug: bool = (false, parse_bool,
|
||||||
|
"Treat all errors that occur as bugs"),
|
||||||
no_analysis: bool = (false, parse_bool,
|
no_analysis: bool = (false, parse_bool,
|
||||||
"Parse and expand the source, but run no analysis"),
|
"Parse and expand the source, but run no analysis"),
|
||||||
extra_plugins: Vec<String> = (Vec::new(), parse_list,
|
extra_plugins: Vec<String> = (Vec::new(), parse_list,
|
||||||
|
@ -843,6 +847,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
|
|
||||||
let parse_only = debugging_opts.parse_only;
|
let parse_only = debugging_opts.parse_only;
|
||||||
let no_trans = debugging_opts.no_trans;
|
let no_trans = debugging_opts.no_trans;
|
||||||
|
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
|
||||||
let no_analysis = debugging_opts.no_analysis;
|
let no_analysis = debugging_opts.no_analysis;
|
||||||
|
|
||||||
if debugging_opts.debug_llvm {
|
if debugging_opts.debug_llvm {
|
||||||
|
@ -1030,6 +1035,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
test: test,
|
test: test,
|
||||||
parse_only: parse_only,
|
parse_only: parse_only,
|
||||||
no_trans: no_trans,
|
no_trans: no_trans,
|
||||||
|
treat_err_as_bug: treat_err_as_bug,
|
||||||
no_analysis: no_analysis,
|
no_analysis: no_analysis,
|
||||||
debugging_opts: debugging_opts,
|
debugging_opts: debugging_opts,
|
||||||
write_dependency_info: write_dependency_info,
|
write_dependency_info: write_dependency_info,
|
||||||
|
|
|
@ -74,18 +74,27 @@ impl Session {
|
||||||
self.diagnostic().handler().fatal(msg)
|
self.diagnostic().handler().fatal(msg)
|
||||||
}
|
}
|
||||||
pub fn span_err(&self, sp: Span, msg: &str) {
|
pub fn span_err(&self, sp: Span, msg: &str) {
|
||||||
|
if self.opts.treat_err_as_bug {
|
||||||
|
self.span_bug(sp, msg);
|
||||||
|
}
|
||||||
match split_msg_into_multilines(msg) {
|
match split_msg_into_multilines(msg) {
|
||||||
Some(msg) => self.diagnostic().span_err(sp, &msg[..]),
|
Some(msg) => self.diagnostic().span_err(sp, &msg[..]),
|
||||||
None => self.diagnostic().span_err(sp, msg)
|
None => self.diagnostic().span_err(sp, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
|
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
|
||||||
|
if self.opts.treat_err_as_bug {
|
||||||
|
self.span_bug(sp, msg);
|
||||||
|
}
|
||||||
match split_msg_into_multilines(msg) {
|
match split_msg_into_multilines(msg) {
|
||||||
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code),
|
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code),
|
||||||
None => self.diagnostic().span_err_with_code(sp, msg, code)
|
None => self.diagnostic().span_err_with_code(sp, msg, code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn err(&self, msg: &str) {
|
pub fn err(&self, msg: &str) {
|
||||||
|
if self.opts.treat_err_as_bug {
|
||||||
|
self.bug(msg);
|
||||||
|
}
|
||||||
self.diagnostic().handler().err(msg)
|
self.diagnostic().handler().err(msg)
|
||||||
}
|
}
|
||||||
pub fn err_count(&self) -> uint {
|
pub fn err_count(&self) -> uint {
|
||||||
|
|
|
@ -73,9 +73,14 @@ use syntax::print::pprust;
|
||||||
pub trait AstConv<'tcx> {
|
pub trait AstConv<'tcx> {
|
||||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
|
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
|
||||||
|
|
||||||
fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>;
|
fn get_item_type_scheme(&self, span: Span, id: ast::DefId)
|
||||||
|
-> Result<ty::TypeScheme<'tcx>, ErrorReported>;
|
||||||
|
|
||||||
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
|
fn get_trait_def(&self, span: Span, id: ast::DefId)
|
||||||
|
-> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>;
|
||||||
|
|
||||||
|
fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
|
||||||
|
-> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
|
||||||
|
|
||||||
/// Return an (optional) substitution to convert bound type parameters that
|
/// Return an (optional) substitution to convert bound type parameters that
|
||||||
/// are in scope into free ones. This function should only return Some
|
/// are in scope into free ones. This function should only return Some
|
||||||
|
@ -683,7 +688,14 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||||
-> Rc<ty::TraitRef<'tcx>>
|
-> Rc<ty::TraitRef<'tcx>>
|
||||||
{
|
{
|
||||||
debug!("ast_path_to_trait_ref {:?}", trait_segment);
|
debug!("ast_path_to_trait_ref {:?}", trait_segment);
|
||||||
let trait_def = this.get_trait_def(trait_def_id);
|
let trait_def = match this.get_trait_def(span, trait_def_id) {
|
||||||
|
Ok(trait_def) => trait_def,
|
||||||
|
Err(ErrorReported) => {
|
||||||
|
// No convenient way to recover from a cycle here. Just bail. Sorry!
|
||||||
|
this.tcx().sess.abort_if_errors();
|
||||||
|
this.tcx().sess.bug("ErrorReported returned, but no errors reports?")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (regions, types, assoc_bindings) = match trait_segment.parameters {
|
let (regions, types, assoc_bindings) = match trait_segment.parameters {
|
||||||
ast::AngleBracketedParameters(ref data) => {
|
ast::AngleBracketedParameters(ref data) => {
|
||||||
|
@ -860,10 +872,15 @@ fn ast_path_to_ty<'tcx>(
|
||||||
item_segment: &ast::PathSegment)
|
item_segment: &ast::PathSegment)
|
||||||
-> Ty<'tcx>
|
-> Ty<'tcx>
|
||||||
{
|
{
|
||||||
let ty::TypeScheme {
|
let tcx = this.tcx();
|
||||||
generics,
|
let (generics, decl_ty) = match this.get_item_type_scheme(span, did) {
|
||||||
ty: decl_ty
|
Ok(ty::TypeScheme { generics, ty: decl_ty }) => {
|
||||||
} = this.get_item_type_scheme(did);
|
(generics, decl_ty)
|
||||||
|
}
|
||||||
|
Err(ErrorReported) => {
|
||||||
|
return tcx.types.err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let substs = ast_path_substs_for_ty(this, rscope,
|
let substs = ast_path_substs_for_ty(this, rscope,
|
||||||
span, param_mode,
|
span, param_mode,
|
||||||
|
@ -1001,20 +1018,17 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||||
return (tcx.types.err, ty_path_def);
|
return (tcx.types.err, ty_path_def);
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut suitable_bounds: Vec<_>;
|
let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
|
||||||
let ty_param_name: ast::Name;
|
|
||||||
{ // contain scope of refcell:
|
|
||||||
let ty_param_defs = tcx.ty_param_defs.borrow();
|
|
||||||
let ty_param_def = &ty_param_defs[ty_param_node_id];
|
|
||||||
ty_param_name = ty_param_def.name;
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME(#20300) -- search where clauses, not bounds
|
// FIXME(#20300) -- search where clauses, not bounds
|
||||||
suitable_bounds =
|
let bounds =
|
||||||
traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds)
|
this.get_type_parameter_bounds(span, ty_param_node_id)
|
||||||
|
.unwrap_or(Vec::new());
|
||||||
|
|
||||||
|
let mut suitable_bounds: Vec<_> =
|
||||||
|
traits::transitive_bounds(tcx, &bounds)
|
||||||
.filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
|
.filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
|
||||||
.collect();
|
.collect();
|
||||||
}
|
|
||||||
|
|
||||||
if suitable_bounds.len() == 0 {
|
if suitable_bounds.len() == 0 {
|
||||||
span_err!(tcx.sess, span, E0220,
|
span_err!(tcx.sess, span, E0220,
|
||||||
|
|
|
@ -97,7 +97,7 @@ use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme};
|
use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme};
|
||||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||||
use middle::ty::{self, HasProjectionTypes, RegionEscape, Ty};
|
use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
|
||||||
use middle::ty::liberate_late_bound_regions;
|
use middle::ty::liberate_late_bound_regions;
|
||||||
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
|
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
|
||||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||||
|
@ -106,7 +106,7 @@ use session::Session;
|
||||||
use {CrateCtxt, lookup_full_def, require_same_types};
|
use {CrateCtxt, lookup_full_def, require_same_types};
|
||||||
use TypeAndSubsts;
|
use TypeAndSubsts;
|
||||||
use lint;
|
use lint;
|
||||||
use util::common::{block_query, indenter, loop_query};
|
use util::common::{block_query, ErrorReported, indenter, loop_query};
|
||||||
use util::ppaux::{self, Repr};
|
use util::ppaux::{self, Repr};
|
||||||
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||||
use util::lev_distance::lev_distance;
|
use util::lev_distance::lev_distance;
|
||||||
|
@ -1206,18 +1206,48 @@ fn check_cast<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||||
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
|
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
|
||||||
|
|
||||||
fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> {
|
fn get_item_type_scheme(&self, _: Span, id: ast::DefId)
|
||||||
ty::lookup_item_type(self.tcx(), id)
|
-> Result<ty::TypeScheme<'tcx>, ErrorReported>
|
||||||
|
{
|
||||||
|
Ok(ty::lookup_item_type(self.tcx(), id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>> {
|
fn get_trait_def(&self, _: Span, id: ast::DefId)
|
||||||
ty::lookup_trait_def(self.tcx(), id)
|
-> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>
|
||||||
|
{
|
||||||
|
Ok(ty::lookup_trait_def(self.tcx(), id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
|
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
|
||||||
Some(&self.inh.param_env.free_substs)
|
Some(&self.inh.param_env.free_substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_type_parameter_bounds(&self,
|
||||||
|
_: Span,
|
||||||
|
node_id: ast::NodeId)
|
||||||
|
-> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
|
||||||
|
{
|
||||||
|
let def = self.tcx().type_parameter_def(node_id);
|
||||||
|
let r = self.inh.param_env.caller_bounds
|
||||||
|
.iter()
|
||||||
|
.filter_map(|predicate| {
|
||||||
|
match *predicate {
|
||||||
|
ty::Predicate::Trait(ref data) => {
|
||||||
|
if data.0.self_ty().is_param(def.space, def.index) {
|
||||||
|
Some(data.to_poly_trait_ref())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
|
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
|
||||||
self.infcx().next_ty_var()
|
self.infcx().next_ty_var()
|
||||||
}
|
}
|
||||||
|
@ -3607,7 +3637,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tcx.sess.span_bug(expr.span,
|
tcx.sess.span_bug(expr.span,
|
||||||
&format!("unbound path {}", expr.repr(tcx))[])
|
&format!("unbound path {}", expr.repr(tcx)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut def = path_res.base_def;
|
let mut def = path_res.base_def;
|
||||||
|
|
|
@ -147,7 +147,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
None => {
|
None => {
|
||||||
self.tcx.sess.bug(
|
self.tcx.sess.bug(
|
||||||
&format!("no default implementation recorded for `{:?}`",
|
&format!("no default implementation recorded for `{:?}`",
|
||||||
item)[]);
|
item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -479,11 +479,10 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
|
||||||
fn clean(&self, cx: &DocContext) -> TyParam {
|
fn clean(&self, cx: &DocContext) -> TyParam {
|
||||||
cx.external_typarams.borrow_mut().as_mut().unwrap()
|
cx.external_typarams.borrow_mut().as_mut().unwrap()
|
||||||
.insert(self.def_id, self.name.clean(cx));
|
.insert(self.def_id, self.name.clean(cx));
|
||||||
let bounds = self.bounds.clean(cx);
|
|
||||||
TyParam {
|
TyParam {
|
||||||
name: self.name.clean(cx),
|
name: self.name.clean(cx),
|
||||||
did: self.def_id,
|
did: self.def_id,
|
||||||
bounds: bounds,
|
bounds: vec![], // these are filled in from the where-clauses
|
||||||
default: self.default.clean(cx),
|
default: self.default.clean(cx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -892,9 +891,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
|
||||||
// Bounds in the type_params and lifetimes fields are repeated in the predicates
|
// Bounds in the type_params and lifetimes fields are repeated in the predicates
|
||||||
// field (see rustc_typeck::collect::ty_generics), so remove them.
|
// field (see rustc_typeck::collect::ty_generics), so remove them.
|
||||||
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
|
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
|
||||||
let mut stp = tp.clone();
|
tp.clean(cx)
|
||||||
stp.bounds = ty::ParamBounds::empty();
|
|
||||||
stp.clean(cx)
|
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
|
let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
|
||||||
let mut srp = rp.clone();
|
let mut srp = rp.clone();
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright 2014 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 equality constraints in a where clause where the type being
|
||||||
|
// equated appears in a supertrait.
|
||||||
|
|
||||||
|
pub trait Vehicle {
|
||||||
|
type Color;
|
||||||
|
|
||||||
|
fn go(&self) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Box {
|
||||||
|
type Color;
|
||||||
|
|
||||||
|
fn mail(&self) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a<C:Vehicle+Box>(_: C::Color) {
|
||||||
|
//~^ ERROR ambiguous associated type `Color` in bounds of `C`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b<C>(_: C::Color) where C : Vehicle+Box {
|
||||||
|
//~^ ERROR ambiguous associated type `Color` in bounds of `C`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c<C>(_: C::Color) where C : Vehicle, C : Box {
|
||||||
|
//~^ ERROR ambiguous associated type `Color` in bounds of `C`
|
||||||
|
}
|
||||||
|
|
||||||
|
struct D<X>;
|
||||||
|
impl<X> D<X> where X : Vehicle {
|
||||||
|
fn d(&self, _: X::Color) where X : Box { }
|
||||||
|
//~^ ERROR ambiguous associated type `Color` in bounds of `X`
|
||||||
|
}
|
||||||
|
|
||||||
|
trait E<X:Vehicle> {
|
||||||
|
fn e(&self, _: X::Color) where X : Box;
|
||||||
|
//~^ ERROR ambiguous associated type `Color` in bounds of `X`
|
||||||
|
|
||||||
|
fn f(&self, _: X::Color) where X : Box { }
|
||||||
|
//~^ ERROR ambiguous associated type `Color` in bounds of `X`
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() { }
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Example cycle where a bound on `T` uses a shorthand for `T`. This
|
||||||
|
// creates a cycle because we have to know the bounds on `T` to figure
|
||||||
|
// out what trait defines `Item`, but we can't know the bounds on `T`
|
||||||
|
// without knowing how to handle `T::Item`.
|
||||||
|
//
|
||||||
|
// Note that in the future cases like this could perhaps become legal,
|
||||||
|
// if we got more fine-grained about our cycle detection or changed
|
||||||
|
// how we handle `T::Item` resolution.
|
||||||
|
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
// Preamble.
|
||||||
|
trait Trait { type Item; }
|
||||||
|
|
||||||
|
struct A<T>
|
||||||
|
where T : Trait,
|
||||||
|
T : Add<T::Item>
|
||||||
|
//~^ ERROR illegal recursive type
|
||||||
|
{
|
||||||
|
data: T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
17
src/test/compile-fail/cycle-trait-supertrait-direct.rs
Normal file
17
src/test/compile-fail/cycle-trait-supertrait-direct.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2015 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 a supertrait cycle where a trait extends itself.
|
||||||
|
|
||||||
|
trait Chromosome: Chromosome {
|
||||||
|
//~^ ERROR unsupported cyclic reference
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
22
src/test/compile-fail/cycle-trait-supertrait-indirect.rs
Normal file
22
src/test/compile-fail/cycle-trait-supertrait-indirect.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2015 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 a supertrait cycle where the first trait we find (`A`) is not
|
||||||
|
// a direct participant in the cycle.
|
||||||
|
|
||||||
|
trait A: B {
|
||||||
|
}
|
||||||
|
|
||||||
|
trait B: C { }
|
||||||
|
|
||||||
|
trait C: B { }
|
||||||
|
//~^ ERROR unsupported cyclic reference
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Various uses of `T::Item` syntax where the bound that supplies
|
||||||
|
// `Item` originates in a where-clause, not the declaration of
|
||||||
|
// `T`. Issue #20300.
|
||||||
|
|
||||||
|
use std::marker::{MarkerTrait, PhantomData};
|
||||||
|
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
|
||||||
|
use std::sync::atomic::Ordering::SeqCst;
|
||||||
|
|
||||||
|
static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
|
// Preamble.
|
||||||
|
trait Trait : MarkerTrait { type Item; }
|
||||||
|
struct Struct;
|
||||||
|
impl Trait for Struct {
|
||||||
|
type Item = u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached on the method which declares `T`.
|
||||||
|
struct A;
|
||||||
|
impl A {
|
||||||
|
fn foo<T>(_x: T::Item) where T: Trait {
|
||||||
|
COUNTER.fetch_add(1, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached on the method to a parameter from the struct.
|
||||||
|
struct B<T>(PhantomData<T>);
|
||||||
|
impl<T> B<T> {
|
||||||
|
fn foo(_x: T::Item) where T: Trait {
|
||||||
|
COUNTER.fetch_add(10, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached to free fn.
|
||||||
|
fn c<T>(_: T::Item) where T : Trait {
|
||||||
|
COUNTER.fetch_add(100, SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached to defaulted and non-defaulted trait method.
|
||||||
|
trait AnotherTrait {
|
||||||
|
fn method<T>(&self, _: T::Item) where T: Trait;
|
||||||
|
fn default_method<T>(&self, _: T::Item) where T: Trait {
|
||||||
|
COUNTER.fetch_add(1000, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct D;
|
||||||
|
impl AnotherTrait for D {
|
||||||
|
fn method<T>(&self, _: T::Item) where T: Trait {
|
||||||
|
COUNTER.fetch_add(10000, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached to trait and impl containing the method.
|
||||||
|
trait YetAnotherTrait<T>
|
||||||
|
where T : Trait
|
||||||
|
{
|
||||||
|
fn method(&self, _: T::Item);
|
||||||
|
fn default_method(&self, _: T::Item) {
|
||||||
|
COUNTER.fetch_add(100000, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct E<T>(PhantomData<T>);
|
||||||
|
impl<T> YetAnotherTrait<T> for E<T>
|
||||||
|
where T : Trait
|
||||||
|
{
|
||||||
|
fn method(&self, _: T::Item) {
|
||||||
|
COUNTER.fetch_add(1000000, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached to inherent impl containing the method.
|
||||||
|
struct F<T>(PhantomData<T>);
|
||||||
|
impl<T> F<T> where T : Trait {
|
||||||
|
fn method(&self, _: T::Item) {
|
||||||
|
COUNTER.fetch_add(10000000, SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where-clause attached to struct.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct G<T> where T : Trait {
|
||||||
|
data: T::Item,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
A::foo::<Struct>(22);
|
||||||
|
B::<Struct>::foo(22);
|
||||||
|
c::<Struct>(22);
|
||||||
|
D.method::<Struct>(22);
|
||||||
|
D.default_method::<Struct>(22);
|
||||||
|
E(PhantomData::<Struct>).method(22);
|
||||||
|
E(PhantomData::<Struct>).default_method(22);
|
||||||
|
F(PhantomData::<Struct>).method(22);
|
||||||
|
G::<Struct> { data: 22, phantom: PhantomData };
|
||||||
|
assert_eq!(COUNTER.load(SeqCst), 11111111);
|
||||||
|
}
|
18
src/test/run-pass/cycle-generic-bound.rs
Normal file
18
src/test/run-pass/cycle-generic-bound.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Regression test for #15477. This test just needs to compile.
|
||||||
|
|
||||||
|
use std::marker::PhantomFn;
|
||||||
|
|
||||||
|
trait Chromosome<X: Chromosome<i32>> : PhantomFn<(Self,X)> {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
23
src/test/run-pass/cycle-trait-type-trait.rs
Normal file
23
src/test/run-pass/cycle-trait-type-trait.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2015 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 a case where a supertrait references a type that references
|
||||||
|
// the original trait. This poses no problem at the moment.
|
||||||
|
|
||||||
|
trait Chromosome: Get<Struct<i32>> {
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Get<A> {
|
||||||
|
fn get(&self) -> A;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct<C:Chromosome> { c: C }
|
||||||
|
|
||||||
|
fn main() { }
|
Loading…
Add table
Reference in a new issue