diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 97e21c152ca2c..e94e0332aa464 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1375,8 +1375,9 @@ rustc_queries! { /// type-checking etc, and it does not normalize specializable /// associated types. /// - /// You should pretty much only use this if an `infcx` is available, - /// otherwise use a `TypingEnv`. + /// You should almost certainly not use this. If you already have an InferCtxt, then + /// you should also probably have a `ParamEnv` from when it was built. If you don't, + /// then you should take a `TypingEnv` to ensure that you handle opaque types correctly. query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } feedable diff --git a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs index 4469050069096..c842e92b5270d 100644 --- a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs +++ b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs @@ -1,5 +1,6 @@ -//! Normalizes MIR in TypingMode::PostAnalysis mode, most notably revealing -//! its opaques. +//! Normalizes MIR in `TypingMode::PostAnalysis`` mode, most notably revealing +//! its opaques. We also only normalize specializable associated items once in +//! `PostAnalysis` mode. use rustc_middle::mir::visit::*; use rustc_middle::mir::*; diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index c2b43416623ed..13ad505bc0483 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -39,9 +39,38 @@ pub enum TypingMode { /// /// We only normalize opaque types which may get defined by the current body, /// which are stored in `defining_opaque_types`. + /// + /// We also refuse to project any associated type that is marked `default`. + /// Non-`default` ("final") types are always projected. This is necessary in + /// general for soundness of specialization. However, we *could* allow projections + /// in fully-monomorphic cases. We choose not to, because we prefer for `default type` + /// to force the type definition to be treated abstractly by any consumers of the + /// impl. Concretely, that means that the following example will + /// fail to compile: + /// + /// ```compile_fail,E0308 + /// #![feature(specialization)] + /// trait Assoc { + /// type Output; + /// } + /// + /// impl Assoc for T { + /// default type Output = bool; + /// } + /// + /// fn main() { + /// let x: <() as Assoc>::Output = true; + /// } + /// ``` Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, /// After analysis, mostly during codegen and MIR optimizations, we're able to - /// reveal all opaque types. + /// reveal all opaque types. As the concrete type should *never* be observable + /// directly by the user, this should not be used by checks which may expose + /// such details to the user. + /// + /// There are some exceptions to this as for example `layout_of` and const-evaluation + /// always run in `PostAnalysis` mode, even when used during analysis. This exposes + /// some information about the underlying type to users, but not the type itself. PostAnalysis, }