mirror of https://github.com/rust-lang/rust.git
Rollup merge of #41939 - eddyb:trait-assoc-const-default, r=petrochenkov
rustc_resolve: don't deny outer type parameters in embedded constants. This solves a problem noted at https://github.com/rust-lang/rust/issues/29646#issuecomment-300929548, where an associated const default in a trait couldn't refer to `Self` or type parameters, due to inaccuracies in lexical scoping. I've also allowed "embedded expressions" (`[T; expr]`, `[x; expr]`, `typeof expr`) to refer to type parameters in scope. *However*, the typesystem still doesn't handle #34344. Fully resolving that issue requires breaking cycles more aggressively (e.g. lazy evaluation), *even* in when the expression doesn't depend on type parameters, to type-check it at all, and then also type-level "constant projections" (in the vein of `{expr}` from const generics).
This commit is contained in:
commit
cfea522226
|
@ -1222,27 +1222,26 @@ fn foo() {
|
|||
"##,
|
||||
|
||||
E0435: r##"
|
||||
A non-constant value was used to initialise a constant.
|
||||
A non-constant value was used in a constant expression.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0435
|
||||
let foo = 42u32;
|
||||
const FOO : u32 = foo; // error: attempt to use a non-constant value in a
|
||||
// constant
|
||||
let foo = 42;
|
||||
let a: [u8; foo]; // error: attempt to use a non-constant value in a constant
|
||||
```
|
||||
|
||||
To fix this error, please replace the value with a constant. Example:
|
||||
|
||||
```
|
||||
const FOO : u32 = 42u32; // ok!
|
||||
let a: [u8; 42]; // ok!
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```
|
||||
const OTHER_FOO : u32 = 42u32;
|
||||
const FOO : u32 = OTHER_FOO; // ok!
|
||||
const FOO: usize = 42;
|
||||
let a: [u8; FOO]; // ok!
|
||||
```
|
||||
"##,
|
||||
|
||||
|
@ -1560,7 +1559,7 @@ register_diagnostics! {
|
|||
// E0157, unused error code
|
||||
// E0257,
|
||||
// E0258,
|
||||
E0402, // cannot use an outer type parameter in this context
|
||||
// E0402, // cannot use an outer type parameter in this context
|
||||
// E0406, merged into 420
|
||||
// E0410, merged into 408
|
||||
// E0413, merged into 530
|
||||
|
|
|
@ -127,8 +127,6 @@ impl Ord for BindingError {
|
|||
enum ResolutionError<'a> {
|
||||
/// error E0401: can't use type parameters from outer function
|
||||
TypeParametersFromOuterFunction,
|
||||
/// error E0402: cannot use an outer type parameter in this context
|
||||
OuterTypeParameterContext,
|
||||
/// error E0403: the name is already used for a type parameter in this type parameter list
|
||||
NameAlreadyUsedInTypeParameterList(Name, &'a Span),
|
||||
/// error E0407: method is not a member of trait
|
||||
|
@ -187,12 +185,6 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
|||
err.span_label(span, "use of type variable from outer function");
|
||||
err
|
||||
}
|
||||
ResolutionError::OuterTypeParameterContext => {
|
||||
struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0402,
|
||||
"cannot use an outer type parameter in this context")
|
||||
}
|
||||
ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => {
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
|
@ -1671,16 +1663,16 @@ impl<'a> Resolver<'a> {
|
|||
this.check_proc_macro_attrs(&trait_item.attrs);
|
||||
|
||||
match trait_item.node {
|
||||
TraitItemKind::Const(_, ref default) => {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
this.visit_ty(ty);
|
||||
|
||||
// Only impose the restrictions of
|
||||
// ConstRibKind if there's an actual constant
|
||||
// ConstRibKind for an actual constant
|
||||
// expression in a provided default.
|
||||
if default.is_some() {
|
||||
if let Some(ref expr) = *default{
|
||||
this.with_constant_rib(|this| {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
} else {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
}
|
||||
TraitItemKind::Method(ref sig, _) => {
|
||||
|
@ -1709,9 +1701,13 @@ impl<'a> Resolver<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
ItemKind::Const(..) | ItemKind::Static(..) => {
|
||||
self.with_constant_rib(|this| {
|
||||
visit::walk_item(this, item);
|
||||
ItemKind::Static(ref ty, _, ref expr) |
|
||||
ItemKind::Const(ref ty, ref expr) => {
|
||||
self.with_item_rib(|this| {
|
||||
this.visit_ty(ty);
|
||||
this.with_constant_rib(|this| {
|
||||
this.visit_expr(expr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1782,13 +1778,21 @@ impl<'a> Resolver<'a> {
|
|||
self.label_ribs.pop();
|
||||
}
|
||||
|
||||
fn with_item_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut Resolver)
|
||||
{
|
||||
self.ribs[ValueNS].push(Rib::new(ItemRibKind));
|
||||
self.ribs[TypeNS].push(Rib::new(ItemRibKind));
|
||||
f(self);
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
fn with_constant_rib<F>(&mut self, f: F)
|
||||
where F: FnOnce(&mut Resolver)
|
||||
{
|
||||
self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
|
||||
self.ribs[TypeNS].push(Rib::new(ConstantItemRibKind));
|
||||
f(self);
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
}
|
||||
|
||||
|
@ -2755,7 +2759,8 @@ impl<'a> Resolver<'a> {
|
|||
for rib in ribs {
|
||||
match rib.kind {
|
||||
NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
|
||||
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind => {
|
||||
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
|
||||
ConstantItemRibKind => {
|
||||
// Nothing to do. Continue.
|
||||
}
|
||||
ItemRibKind => {
|
||||
|
@ -2767,14 +2772,6 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
return Def::Err;
|
||||
}
|
||||
ConstantItemRibKind => {
|
||||
// see #9186
|
||||
if record_used {
|
||||
resolve_error(self, span,
|
||||
ResolutionError::OuterTypeParameterContext);
|
||||
}
|
||||
return Def::Err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
|
||||
fn main () {
|
||||
let foo = 42u32;
|
||||
const FOO : u32 = foo; //~ ERROR E0435
|
||||
let _: [u8; foo]; //~ ERROR E0435
|
||||
//~| NOTE non-constant used with constant
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ impl Foo for Def {
|
|||
|
||||
pub fn test<A: Foo, B: Foo>() {
|
||||
let _array = [4; <A as Foo>::Y];
|
||||
//~^ ERROR cannot use an outer type parameter in this context [E0402]
|
||||
//~^ ERROR the trait bound `A: Foo` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -26,7 +26,7 @@ impl Foo for Def {
|
|||
|
||||
pub fn test<A: Foo, B: Foo>() {
|
||||
let _array: [u32; <A as Foo>::Y];
|
||||
//~^ ERROR cannot use an outer type parameter in this context [E0402]
|
||||
//~^ ERROR the trait bound `A: Foo` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -14,7 +14,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
|
|||
|
||||
fn foo<T>() {
|
||||
static a: Bar<T> = Bar::What;
|
||||
//~^ ERROR cannot use an outer type parameter in this context
|
||||
//~^ ERROR can't use type parameters from outer function; try using a local type parameter instead
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
fn main() {
|
||||
let foo = 42u32;
|
||||
const FOO : u32 = foo;
|
||||
//~^ ERROR attempt to use a non-constant value in a constant
|
||||
//~^ ERROR can't capture dynamic environment
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
|||
let foo = 100;
|
||||
|
||||
static y: isize = foo + 1;
|
||||
//~^ ERROR attempt to use a non-constant value in a constant
|
||||
//~^ ERROR can't capture dynamic environment
|
||||
|
||||
println!("{}", y);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
fn f(x:isize) {
|
||||
static child: isize = x + 1;
|
||||
//~^ ERROR attempt to use a non-constant value in a constant
|
||||
//~^ ERROR can't capture dynamic environment
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -16,7 +16,7 @@ trait PTrait {
|
|||
impl PTrait for P {
|
||||
fn getChildOption(&self) -> Option<Box<P>> {
|
||||
static childVal: Box<P> = self.child.get();
|
||||
//~^ ERROR attempt to use a non-constant value in a constant
|
||||
//~^ ERROR can't capture dynamic environment
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
trait Dim {
|
||||
fn dim() -> usize;
|
||||
}
|
||||
|
||||
enum Dim3 {}
|
||||
|
||||
impl Dim for Dim3 {
|
||||
fn dim() -> usize {
|
||||
3
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let array: [usize; Dim3::dim()]
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
= [0; Dim3::dim()];
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
}
|
|
@ -22,12 +22,7 @@ impl Dim for Dim3 {
|
|||
|
||||
pub struct Vector<T, D: Dim> {
|
||||
entries: [T; D::dim()]
|
||||
//~^ ERROR cannot use an outer type parameter in this context
|
||||
//~^ ERROR no associated item named `dim` found for type `D` in the current scope
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let array: [usize; Dim3::dim()]
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
= [0; Dim3::dim()];
|
||||
//~^ ERROR calls in constants are limited to constant functions
|
||||
}
|
||||
fn main() {}
|
||||
|
|
|
@ -37,6 +37,10 @@ fn sub<A: Foo, B: Foo>() -> i32 {
|
|||
A::X - B::X
|
||||
}
|
||||
|
||||
trait Bar: Foo {
|
||||
const Y: i32 = Self::X;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(11, Abc::X);
|
||||
assert_eq!(97, Def::X);
|
||||
|
|
Loading…
Reference in New Issue