Description
Currently, check_static_recursion
is run after resolve
, but before typeck
. This made sense before, because after resolve
it was possible to determine which constants referenced one another, and running before typeck
ensured that we don't fall into an infinite loop during type checking. However, when referencing an associated constant with some UFCS forms, we can't resolve the constant until typeck
, meaning that check_static_recursion
can't always tell when a recursive definition is present. On top of that, this check is not currently working right even for inherent impls, where it should be possible to discover a problem ahead of typeck
running.
A set of test cases:
// 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.
#![feature(associated_consts)]
trait Foo {
const BAR: u32;
}
// Check for recursion involving references to trait-associated const.
const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR; //~ ERROR E0265
struct GlobalTraitRef;
impl Foo for GlobalTraitRef {
const BAR: u32 = TRAIT_REF_BAR; //~ ERROR E0265
}
// Check for recursion involving references to impl-associated const.
const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; //~ ERROR E0265
struct GlobalImplRef;
impl GlobalImplRef {
const BAR: u32 = IMPL_REF_BAR; //~ ERROR E0265
}
// Check for recursion involving references to trait-associated const default.
trait FooDefault {
const BAR: u32 = DEFAULT_REF_BAR; //~ ERROR E0265
}
const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR; //~ ERROR E0265
struct GlobalDefaultRef;
impl FooDefault for GlobalDefaultRef {}
fn main() {}
The above cases should all fail in the recursion check, but they all compile successfully! If any of the constants are actually used in a context that requires the compiler to evaluate them, there will be an ICE (specifically, the compiler enters an infinite loop that ends up blowing the stack).
Update
playground link: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=76e9edaf2827806e18a557f37bc930ea
This issue has been assigned to @Daniel-Worrall via this comment.