Change:
The following doesn't compile, as it tries to assign a concrete instead of : Removing the type parameter makes it work - is only used for the associated type anyway: AFAICT, the selection results in in the first case, and in the second case, and we refuse to allow to be parameterized by in the former case, even though it's only used to satisfy the sugary form of the trait.
Is this the same issue as with the impls for not matching ?
I'm trying to decide if this is an actual bug :) It does seem like the "HR capture" logic is being unnecessarily conservative. Let me poke at the debug logs and see if that reveals to me why it is rejecting the impl when you include but not if you don't (also, it works if you do ).
I believe it breaks for type parameters which cannot be extracted from the , i.e. . You should be able to relate multiple argument types, but not the return type (because it's an associated type and not part of the ).
Hmm, the problem is a bit of a subtle one and, in this particular example, tied to the associated type projection. (No I don't, see update below.) No doubt this is already filed somewhere under another guise. I'm not sure of the best fix, but let me lay out how the problem arises in terms of what the compiler actually does. We start out with a trait reference to solve: We match this against the impl Which, internally, is lowered to: In so doing, we first "open" the binder, so that the trait we are searching for becomes: where is a region variable. We then check whether we can match this against the impl in question. We can, with and . is left unconstrained. The where clauses on the impl are always processed after we perform the initial match. So we wind up saying that the impl applies and that we now have various subobligations. The region variable appears in some of those, and in that case we "regeneralize" by adding back a binder so that becomes a bound region again: Note that is what was substituted for the variable (but never constrained). And this is where the problem arises. I think that the basic strategy here is somewhat wrong. It would be OK in the absence of variables like , which do not appear in the trait reference but which are constrained by projections, but it's wrong now. The problem is that was created "inside" the binder along with with and but, unlike those other variables, it was never constrained. Thus we kind of silently promote it to live outside the scope of the , since it is completely unconstrained. This is not necessarily wrong I guess but it is overly conservative. One possible fix here would be to recursively (and before returning) handle the projection constraints, so that winds up being "determined" to be , which could then be generalized to wherever it appeared. That may be the best short term fix at least, though I am not so keen on it overall because I don't like doing work recursively like that. If we had had lazy normalization, this would be much easier, because then we could just unify with , which would then be generalized to a bound region as needed. That's probably my preferred fix, presuming it can be made to work. This is basically the same as processing the projection constraint recursively, except that we could defer the actual normalization until later (and we may never have to do it). (The other solutions I can imagine are quite a bit more complicated. It seems like you would need to capture, in the tree, what variables are bound where. What makes this hard is that is shared across two obligations.) UPDATE: Remove sentence I don't think. I think that for this problem to arise you really need an associated type, since you need a type variable that is not found in the trait reference, which is otherwise verboten.
cc -- this seems related to the changes you made to order projection predicates earlier in the list. Does make sense to you?
I am not sure we should not evaluate associated type projections recursively - RFC447 basically forces this to work. Unfortunately, it will work imperfectly without lazy normalization, because we can't represent a constraint like .
On Thu, Jan 14, 2016 at 12:54:36PM -0800, arielb1 wrote: Sorry, the double negative in this sentence is throwing me a bit. I'm not sure I understand what you are saying. Are you saying my proposed solution would or would not work? Also, when you say evaluate, I presume you are not referring to the family of fns in but just using a generic verb.
Can you elaborate just a bit on this? When does this kind of constraint arise?
Recursively applying constraining-projections during confirmation should work, except for the type-inference case.
Sorry for not replying. I'm afraid I still don't quite follow you, so let me try and work it out. First off, I guess you meant to have , like so, and probably : I'm not quite sure what the last line means, but if we were to follow the model of the original problem, we'd start with something to prove like . "Opening" the and matching this against the impl yields: and hence . This suggests that we would translate the where clauses on the impl to: which we would could then cover back up as: This all seems...OK. Ah, wait, I guess your point is that we would need to normalize the . I feel like we have issues normalizing under for binders still, right?
I was bitten by this bug... simplifying a lot, my code looked like this (): but this isn't lifetime-polymporphic: produces: but if you make the iterator item type a type argument, then it all works: so I need to rewrite a lot of code to take an extra type argument in order to be lifetime-polymorphic!
Both the original example and asajeffrey's example compile now.

Discussion:
self } <ins> /// Configuration for the child process’s standard input (stdin) handle. /// /// See [`std::process::Command::stdin`]. pub fn stdin<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self { self.cmd.stdin(cfg); self } /// Configuration for the child process’s standard output (stdout) handle. /// /// See [`std::process::Command::stdout`]. pub fn stdout<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self { self.cmd.stdout(cfg); self } /// Configuration for the child process’s standard error (stderr) handle. /// /// See [`std::process::Command::stderr`]. pub fn stderr<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self { self.cmd.stderr(cfg); self } </ins> /// Inspect what the underlying [`Command`] is up to the /// current construction. pub fn inspect<I>(&mut self, inspector: I) -> &mut Self

run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile <del> run-make/emit-to-stdout/Makefile </del> run-make/extern-fn-reachable/Makefile run-make/incr-add-rust-src-component/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile

ui/consts/issue-73976-monomorphic.rs ui/consts/issue-73976-polymorphic.rs ui/consts/issue-76064.rs <del> ui/consts/issue-77062-large-zst-array.rs </del> ui/consts/issue-78655.rs ui/consts/issue-79137-monomorphic.rs ui/consts/issue-79137-toogeneric.rs

<del> include ../tools.mk SRC=test.rs OUT=$(TMPDIR)/out all: asm llvm-ir dep-info mir llvm-bc obj metadata link multiple-types multiple-types-option-o asm: $(OUT) $(RUSTC) --emit asm=$(OUT)/$@ $(SRC) $(RUSTC) --emit asm=- $(SRC) | diff - $(OUT)/$@ llvm-ir: $(OUT) $(RUSTC) --emit llvm-ir=$(OUT)/$@ $(SRC) $(RUSTC) --emit llvm-ir=- $(SRC) | diff - $(OUT)/$@ dep-info: $(OUT) $(RUSTC) -Z dep-info-omit-d-target=yes --emit dep-info=$(OUT)/$@ $(SRC) $(RUSTC) --emit dep-info=- $(SRC) | diff - $(OUT)/$@ mir: $(OUT) $(RUSTC) --emit mir=$(OUT)/$@ $(SRC) $(RUSTC) --emit mir=- $(SRC) | diff - $(OUT)/$@ llvm-bc: $(OUT) $(RUSTC) --emit llvm-bc=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true diff $(OUT)/$@ emit-llvm-bc.stderr obj: $(OUT) $(RUSTC) --emit obj=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true diff $(OUT)/$@ emit-obj.stderr # For metadata output, a temporary directory will be created to hold the temporary # metadata file. But when output is stdout, the temporary directory will be located # in the same place as $(SRC), which is mounted as read-only in the tests. Thus as # a workaround, $(SRC) is copied to the test output directory $(OUT) and we compile # it there. metadata: $(OUT) cp $(SRC) $(OUT) (cd $(OUT); $(RUSTC) --emit metadata=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true) diff $(OUT)/$@ emit-metadata.stderr link: $(OUT) $(RUSTC) --emit link=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true diff $(OUT)/$@ emit-link.stderr multiple-types: $(OUT) $(RUSTC) --emit asm=- --emit llvm-ir=- --emit dep-info=- --emit mir=- $(SRC) 2>$(OUT)/$@ || true diff $(OUT)/$@ emit-multiple-types.stderr multiple-types-option-o: $(OUT) $(RUSTC) -o - --emit asm,llvm-ir,dep-info,mir $(SRC) 2>$(OUT)/$@ || true diff $(OUT)/$@ emit-multiple-types.stderr $(OUT): mkdir -p $(OUT) </del>

<ins> //! If `-o -` or `--emit KIND=-` is provided, output should be written to stdout //! instead. Binary output (`obj`, `llvm-bc`, `link` and `metadata`) //! being written this way will result in an error if stdout is a tty. //! Multiple output types going to stdout will trigger an error too, //! as they would all be mixed together. //! //! See <https://github.com/rust-lang/rust/pull/111626>. use std::fs::File; use run_make_support::{diff, run_in_tmpdir, rustc}; // Test emitting text outputs to stdout works correctly fn run_diff(name: &str, file_args: &[&str]) { rustc().emit(format!("{name}={name}")).input("test.rs").args(file_args).run(); let out = rustc().emit(format!("{name}=-")).input("test.rs").run().stdout_utf8(); diff().expected_file(name).actual_text("stdout", &out).run(); } // Test that emitting binary formats to a terminal gives the correct error fn run_terminal_err_diff(name: &str) { #[cfg(not(windows))] let terminal = File::create("/dev/ptmx").unwrap(); // FIXME: If this test fails and the compiler does print to the console, // then this will produce a lot of output. // We should spawn a new console instead to print stdout. #[cfg(windows)] let terminal = File::options().read(true).write(true).open(r".CONOUT$").unwrap(); let err = File::create(name).unwrap(); rustc().emit(format!("{name}=-")).input("test.rs").stdout(terminal).stderr(err).run_fail(); diff().expected_file(format!("emit-{name}.stderr")).actual_file(name).run(); } fn main() { run_in_tmpdir(|| { run_diff("asm", &[]); run_diff("llvm-ir", &[]); run_diff("dep-info", &["-Zdep-info-omit-d-target=yes"]); run_diff("mir", &[]); run_terminal_err_diff("llvm-bc"); run_terminal_err_diff("obj"); run_terminal_err_diff("metadata"); run_terminal_err_diff("link"); // Test error for emitting multiple types to stdout rustc() .input("test.rs") .emit("asm=-") .emit("llvm-ir=-") .emit("dep-info=-") .emit("mir=-") .stderr(File::create("multiple-types").unwrap()) .run_fail(); diff().expected_file("emit-multiple-types.stderr").actual_file("multiple-types").run(); // Same as above, but using `-o` rustc() .input("test.rs") .output("-") .emit("asm,llvm-ir,dep-info,mir") .stderr(File::create("multiple-types-option-o").unwrap()) .run_fail(); diff() .expected_file("emit-multiple-types.stderr") .actual_file("multiple-types-option-o") .run(); // Test that `-o -` redirected to a file works correctly (#26719) rustc().input("test.rs").output("-").stdout(File::create("out-stdout").unwrap()).run(); }); } </ins>

<del> //@ build-pass fn main() { let _ = &[(); usize::MAX]; } </del>

<ins> //@ build-pass pub static FOO: [(); usize::MAX] = [(); usize::MAX]; fn main() { let _ = &[(); usize::MAX]; } </ins>

<ins> //@ check-pass //! Tests that associated type projections normalize properly in the presence of HRTBs. //! Original issue: <https://github.com/rust-lang/rust/issues/30472> pub trait MyFrom<T> {} impl<T> MyFrom<T> for T {} pub trait MyInto<T> {} impl<T, U> MyInto<U> for T where U: MyFrom<T> {} pub trait A<'self_> { type T; } pub trait B: for<'self_> A<'self_> { // Originally caused the `type U = usize` example below to fail with a type mismatch error type U: for<'self_> MyFrom<<Self as A<'self_>>::T>; } pub struct M; impl<'self_> A<'self_> for M { type T = usize; } impl B for M { type U = usize; } fn main() {} </ins>

<ins> //@ check-pass //! Tests that a HRTB + FnOnce bound involving an associated type don't prevent //! a function pointer from implementing `Fn` traits. //! Test for <https://github.com/rust-lang/rust/issues/28994> trait LifetimeToType<'a> { type Out; } impl<'a> LifetimeToType<'a> for () { type Out = &'a (); } fn id<'a>(val: &'a ()) -> <() as LifetimeToType<'a>>::Out { val } fn assert_fn<F: for<'a> FnOnce(&'a ()) -> <() as LifetimeToType<'a>>::Out>(_func: F) { } fn main() { assert_fn(id); } </ins>

<ins> //@ check-pass //! Tests that HRTB impl selection covers type parameters not directly related //! to the trait. //! Test for <https://github.com/rust-lang/rust/issues/30867> #![crate_type = "lib"] trait Unary<T> {} impl<T, U, F: Fn(T) -> U> Unary<T> for F {} fn unary<F: for<'a> Unary<&'a T>, T>() {} pub fn test<F: for<'a> Fn(&'a i32) -> &'a i32>() { unary::<F, i32>() } </ins>