improve the printing of substs and trait-refs
This commit is contained in:
parent
31247e5a0b
commit
b23648fe4a
118 changed files with 350 additions and 291 deletions
|
@ -19,6 +19,7 @@ use ty::TyClosure;
|
||||||
use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
|
use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
@ -67,93 +68,18 @@ pub enum Ns {
|
||||||
Value
|
Value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
fn number_of_supplied_defaults<'tcx, GG>(tcx: &ty::TyCtxt<'tcx>,
|
||||||
substs: &subst::Substs,
|
substs: &subst::Substs,
|
||||||
did: DefId,
|
space: subst::ParamSpace,
|
||||||
ns: Ns,
|
|
||||||
projections: &[ty::ProjectionPredicate],
|
|
||||||
get_generics: GG)
|
get_generics: GG)
|
||||||
-> fmt::Result
|
-> usize
|
||||||
where GG: for<'tcx> FnOnce(&TyCtxt<'tcx>) -> ty::Generics<'tcx>
|
where GG: FnOnce(&TyCtxt<'tcx>) -> ty::Generics<'tcx>
|
||||||
{
|
{
|
||||||
if let (Ns::Value, Some(self_ty)) = (ns, substs.self_ty()) {
|
|
||||||
write!(f, "<{} as ", self_ty)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (fn_trait_kind, verbose, last_name) = ty::tls::with(|tcx| {
|
|
||||||
let (did, last_name) = if ns == Ns::Value {
|
|
||||||
// Try to get the impl/trait parent, if this is an
|
|
||||||
// associated value item (method or constant).
|
|
||||||
tcx.trait_of_item(did).or_else(|| tcx.impl_of_method(did))
|
|
||||||
.map_or((did, None), |parent| (parent, Some(tcx.item_name(did))))
|
|
||||||
} else {
|
|
||||||
(did, None)
|
|
||||||
};
|
|
||||||
write!(f, "{}", tcx.item_path_str(did))?;
|
|
||||||
Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose(), last_name))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut empty = true;
|
|
||||||
let mut start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
|
|
||||||
if empty {
|
|
||||||
empty = false;
|
|
||||||
write!(f, "{}", start)
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", cont)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
for region in &substs.regions {
|
|
||||||
start_or_continue(f, "<", ", ")?;
|
|
||||||
write!(f, "{:?}", region)?;
|
|
||||||
}
|
|
||||||
for &ty in &substs.types {
|
|
||||||
start_or_continue(f, "<", ", ")?;
|
|
||||||
write!(f, "{}", ty)?;
|
|
||||||
}
|
|
||||||
for projection in projections {
|
|
||||||
start_or_continue(f, "<", ", ")?;
|
|
||||||
write!(f, "{}={}",
|
|
||||||
projection.projection_ty.item_name,
|
|
||||||
projection.ty)?;
|
|
||||||
}
|
|
||||||
return start_or_continue(f, "", ">");
|
|
||||||
}
|
|
||||||
|
|
||||||
if fn_trait_kind.is_some() && projections.len() == 1 {
|
|
||||||
let projection_ty = projections[0].ty;
|
|
||||||
if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
|
|
||||||
return fn_sig(f, args, false, ty::FnConverging(projection_ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &r in &substs.regions {
|
|
||||||
start_or_continue(f, "<", ", ")?;
|
|
||||||
let s = r.to_string();
|
|
||||||
if s.is_empty() {
|
|
||||||
// This happens when the value of the region
|
|
||||||
// parameter is not easily serialized. This may be
|
|
||||||
// because the user omitted it in the first place,
|
|
||||||
// or because it refers to some block in the code,
|
|
||||||
// etc. I'm not sure how best to serialize this.
|
|
||||||
write!(f, "'_")?;
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", s)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is important to execute this conditionally, only if -Z
|
|
||||||
// verbose is false. Otherwise, debug logs can sometimes cause
|
|
||||||
// ICEs trying to fetch the generics early in the pipeline. This
|
|
||||||
// is kind of a hacky workaround in that -Z verbose is required to
|
|
||||||
// avoid those ICEs.
|
|
||||||
let tps = substs.types.get_slice(subst::TypeSpace);
|
|
||||||
let num_defaults = ty::tls::with(|tcx| {
|
|
||||||
let generics = get_generics(tcx);
|
let generics = get_generics(tcx);
|
||||||
|
|
||||||
let has_self = substs.self_ty().is_some();
|
let has_self = substs.self_ty().is_some();
|
||||||
let ty_params = generics.types.get_slice(subst::TypeSpace);
|
let ty_params = generics.types.get_slice(space);
|
||||||
|
let tps = substs.types.get_slice(space);
|
||||||
if ty_params.last().map_or(false, |def| def.default.is_some()) {
|
if ty_params.last().map_or(false, |def| def.default.is_some()) {
|
||||||
let substs = tcx.lift(&substs);
|
let substs = tcx.lift(&substs);
|
||||||
ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| {
|
ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| {
|
||||||
|
@ -169,7 +95,8 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let default = tcx.lift(&default);
|
let default = tcx.lift(&default);
|
||||||
substs.and_then(|substs| default.subst(tcx, substs)) == Some(actual)
|
substs.and_then(|substs| default.subst(tcx, substs))
|
||||||
|
== Some(actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => false
|
None => false
|
||||||
|
@ -178,9 +105,89 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
for &ty in &tps[..tps.len() - num_defaults] {
|
pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
||||||
|
substs: &subst::Substs,
|
||||||
|
did: DefId,
|
||||||
|
ns: Ns,
|
||||||
|
projections: &[ty::ProjectionPredicate],
|
||||||
|
get_generics: GG)
|
||||||
|
-> fmt::Result
|
||||||
|
where GG: for<'tcx> FnOnce(&TyCtxt<'tcx>) -> ty::Generics<'tcx>
|
||||||
|
{
|
||||||
|
if let (Ns::Value, Some(self_ty)) = (ns, substs.self_ty()) {
|
||||||
|
write!(f, "<{} as ", self_ty)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (fn_trait_kind, verbose, item_name) = ty::tls::with(|tcx| {
|
||||||
|
let (did, item_name) = if ns == Ns::Value {
|
||||||
|
// Try to get the impl/trait parent, if this is an
|
||||||
|
// associated value item (method or constant).
|
||||||
|
tcx.trait_of_item(did).or_else(|| tcx.impl_of_method(did))
|
||||||
|
.map_or((did, None), |parent| (parent, Some(tcx.item_name(did))))
|
||||||
|
} else {
|
||||||
|
(did, None)
|
||||||
|
};
|
||||||
|
write!(f, "{}", tcx.item_path_str(did))?;
|
||||||
|
Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose(), item_name))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
|
||||||
|
let projection_ty = projections[0].ty;
|
||||||
|
if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
|
||||||
|
return fn_sig(f, args, false, ty::FnConverging(projection_ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let empty = Cell::new(true);
|
||||||
|
let start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
|
||||||
|
if empty.get() {
|
||||||
|
empty.set(false);
|
||||||
|
write!(f, "{}", start)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", cont)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let print_region = |f: &mut fmt::Formatter, region: &ty::Region| -> _ {
|
||||||
|
if verbose {
|
||||||
|
write!(f, "{:?}", region)
|
||||||
|
} else {
|
||||||
|
let s = region.to_string();
|
||||||
|
if s.is_empty() {
|
||||||
|
// This happens when the value of the region
|
||||||
|
// parameter is not easily serialized. This may be
|
||||||
|
// because the user omitted it in the first place,
|
||||||
|
// or because it refers to some block in the code,
|
||||||
|
// etc. I'm not sure how best to serialize this.
|
||||||
|
write!(f, "'_")
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for region in substs.regions.get_slice(subst::TypeSpace) {
|
||||||
|
start_or_continue(f, "<", ", ")?;
|
||||||
|
print_region(f, region)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_supplied_defaults = if verbose {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
// It is important to execute this conditionally, only if -Z
|
||||||
|
// verbose is false. Otherwise, debug logs can sometimes cause
|
||||||
|
// ICEs trying to fetch the generics early in the pipeline. This
|
||||||
|
// is kind of a hacky workaround in that -Z verbose is required to
|
||||||
|
// avoid those ICEs.
|
||||||
|
ty::tls::with(|tcx| {
|
||||||
|
number_of_supplied_defaults(tcx, substs, subst::TypeSpace, get_generics)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let tps = substs.types.get_slice(subst::TypeSpace);
|
||||||
|
|
||||||
|
for &ty in &tps[..tps.len() - num_supplied_defaults] {
|
||||||
start_or_continue(f, "<", ", ")?;
|
start_or_continue(f, "<", ", ")?;
|
||||||
write!(f, "{}", ty)?;
|
write!(f, "{}", ty)?;
|
||||||
}
|
}
|
||||||
|
@ -196,21 +203,28 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
|
||||||
|
|
||||||
// For values, also print their name and type parameters.
|
// For values, also print their name and type parameters.
|
||||||
if ns == Ns::Value {
|
if ns == Ns::Value {
|
||||||
|
empty.set(true);
|
||||||
|
|
||||||
if substs.self_ty().is_some() {
|
if substs.self_ty().is_some() {
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = last_name {
|
if let Some(item_name) = item_name {
|
||||||
write!(f, "::{}", name)?;
|
write!(f, "::{}", item_name)?;
|
||||||
}
|
}
|
||||||
let tps = substs.types.get_slice(subst::FnSpace);
|
|
||||||
if !tps.is_empty() {
|
for region in substs.regions.get_slice(subst::FnSpace) {
|
||||||
write!(f, "::<{}", tps[0])?;
|
start_or_continue(f, "::<", ", ")?;
|
||||||
for ty in &tps[1..] {
|
print_region(f, region)?;
|
||||||
write!(f, ", {}", ty)?;
|
|
||||||
}
|
}
|
||||||
write!(f, ">")?;
|
|
||||||
|
// FIXME: consider being smart with defaults here too
|
||||||
|
for ty in substs.types.get_slice(subst::FnSpace) {
|
||||||
|
start_or_continue(f, "::<", ", ")?;
|
||||||
|
write!(f, "{}", ty)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_or_continue(f, "", ">")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -997,9 +1011,7 @@ impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> fmt::Display for ty::TraitPredicate<'tcx> {
|
impl<'tcx> fmt::Display for ty::TraitPredicate<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} : {}",
|
write!(f, "{}: {}", self.trait_ref.self_ty(), self.trait_ref)
|
||||||
self.trait_ref.self_ty(),
|
|
||||||
self.trait_ref)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn main() {
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 2,
|
y: 2,
|
||||||
};
|
};
|
||||||
for x in bogus { //~ ERROR `MyStruct : std::iter::Iterator`
|
for x in bogus { //~ ERROR `MyStruct: std::iter::Iterator` is not satisfied
|
||||||
drop(x);
|
drop(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
src/test/compile-fail/substs-verbose.rs
Normal file
47
src/test/compile-fail/substs-verbose.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
//
|
||||||
|
// compile-flags: -Z verbose
|
||||||
|
|
||||||
|
// TODO nikomatsakis: test with both verbose and without
|
||||||
|
|
||||||
|
trait Foo<'b, 'c, S=u32> {
|
||||||
|
fn bar<'a, T>() where T: 'a {}
|
||||||
|
fn baz() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b,T,S> Foo<'a, 'b, S> for T {}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn foo<'z>() where &'z (): Sized {
|
||||||
|
let x: () = <i8 as Foo<'static, 'static, u8>>::bar::<'static, char>;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| expected `()`
|
||||||
|
//~| found `fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::bar::<ReStatic, char>}`
|
||||||
|
|
||||||
|
let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| expected `()`
|
||||||
|
//~| found `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>}`
|
||||||
|
|
||||||
|
let x: () = <i8 as Foo<'static, 'static, u8>>::baz;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| expected `()`
|
||||||
|
//~| found `fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::baz}`
|
||||||
|
|
||||||
|
let x: () = foo::<'static>;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| expected `()`
|
||||||
|
//~| found `fn() {foo::<ReStatic>}`
|
||||||
|
|
||||||
|
<str as Foo<u8>>::bar;
|
||||||
|
//~^ ERROR `str: std::marker::Sized` is not satisfied
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue