jiebi/CodeConvo huggingface dataset:
Code change:
<ins> // 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. // Test that methods from shadowed traits cannot be used mod foo { pub trait T { fn f(&self) {} } impl T for () {} } mod bar { pub use foo::T; } fn main() { pub use bar::*; struct T; ().f() //~ ERROR no method } </ins>

Related discussion:
text: This compiles: but this doesn't: More generally, a shadowed trait's methods are usable if it is shadowed by an item, but not if it is shadowed by an import. Should methods from shadowed traits be usable?
cc
cc
Nominating for discussion at meeting. Clearly we should be consistent. I'm inclined to think that they should not be available, ever.
I'm of the same thoughts as A new "thing" with the same name as another outer "thing" should not inherit/infer/have/etc. any part of that outer thing. This is the case with , but—according to the presented opinion—it seems like it needs to be made consistent for trait bindings, right?
Is there a reason to shadow traits by name? What happens here is that it must find a method named among the imported traits, and that name has not been shadowed in any way, so it should be callable.
Well, that's the question, isn't it. Imagine then that did have an method -- would you prefer an ambiguity error here, or success?
Ambiguity error if was implemented for in the example (and this error is already implemented). Otherwise it doesn't interfere in any way.
Another more challenging example might be: should the methods from be available, given that it is shadowed by ?
My feeling is that the simplest rule is to say that methods come from "traits that are in scope", and shadowed traits are not in scope. This interpretation is shadowing of items from prelude and globs, which seem like they should clearly not count towards method resolution.
Discussed in meeting and settled on "methods from shadowed traits should be unavailable". triage: P-medium
We also want methods from to be unavailable (from your more challenging example), right?
Code change:
<ins> warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/nested-apit-mentioning-outer-bound-var.rs:1:12 | LL | #![feature(non_lifetime_binders)] |            ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information = note: `#[warn(incomplete_features)]` on by default error: `impl Trait` can only mention type parameters from an fn or impl --> $DIR/nested-apit-mentioning-outer-bound-var.rs:8:52 | LL | fn uwu(_: impl for<T> Trait<(), Assoc = impl Trait<T>>) {} |                    - type parameter declared here  ^ error: aborting due to previous error; 1 warning emitted </ins>

Related discussion:
text: <!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
minimized
Bisected to :sweatsmile:
Code change:
// Once we're done with llvm 14 and earlier, this test can be deleted. <del> #![crate_type="lib"] </del> <ins> #![crate_type = "lib"] </ins> use std::mem::MaybeUninit;

Related discussion:
text: The following code generates some really awful LLVM IR: The same happens with . Cc who made me write these tests, and
Feels like an LLVM limitation to me. It should be replacing the with a (or a of poison when that becomes available).
For reference: LLVM is capable of optimizing a memcpy of undef alloca away, this just runs into the usual limitation that all of memcpyopt doesn't work across BBs.
This is such a long-standing issue. Seems like it might be wise to have someone working on fixing this.
Someone has already worked on this, see It's a bit hard to track, but unfortunately this got reverted again (multiple times). I suspect that this is only going to get really resolved once memcpyopt moves to memssa -- which someone has also worked on in the past (), but which never really went anywhere.
The alloca and memcpy are no longer present on nightly, as a result of .
The FIXME in the test is still there, needs a test.
Code change:
// and about 2 * (len1 + len2) comparisons in the worst case // while `extend` takes O(len2 * log(len1)) operations // and about 1 * len2 * log_2(len1) comparisons in the worst case, <del> // assuming len1 >= len2. </del> <ins> // assuming len1 >= len2. For larger heaps, the crossover point // no longer follows this reasoning and was determined empirically. </ins> #[inline] fn better_to_rebuild(len1: usize, len2: usize) -> bool { <del> 2 * (len1 + len2) < len2 * log2_fast(len1) </del> <ins> let tot_len = len1 + len2; if tot_len <= 2048 { 2 * tot_len < len2 * log2_fast(len1) } else { 2 * tot_len < len2 * 11 } </ins> } if better_to_rebuild(self.len(), other.len()) {

Related discussion:
text: The uses a heuristic based on the worst-case number of comparisons to determine between two strategies: , equivalent to pushing all elements of the other heap. the vector of the other heap and rebuilding the heap from scratch. I've done some benchmarking, and it turns out that method 1 (based on ) is always faster for two heaps based on randomly shuffled data &ndash; on the computers I've tested it on, anyway. I've included images of below: first the current strategy, then the strategy (method 1). In the benchmarks, two heaps are merged, one containing the number of elements on the x-axis, the other containing 100,000 minus that number (for the rightmost data points both heaps are equal in size). The red line (sometimes hiding behind the green one) is in both images that corresponding to , the other lines are not relevant to this issue (they aren't standard library types). ! ! From the jump in performance in the first graph, you can clearly see when the switch between the two approaches happens. Graphs are similar for smaller heaps, I didn't test larger ones. It's possible method 2 is faster under other circumstances (maybe if one of the heaps contains mostly very small/large elements?), especially if both heaps are (almost) equal in size. However, I think the benchmark is more close to the "average" real-world use case than such a case would be (I'd be happy to be proven wrong about this, though). <details<summarySimplification of the benchmark that only runs the parts relevant for this issue</summary</details
The comment suggests that the rebuild strategy is more efficient if at least one of the following is true: comparisons are very expensive the appended heap is much much larger than self but self must still contain a handful of elements so that the logarithm is 2 You can see how the slope of the append method is lower, so its advantage would show if you extended your benchmark by an order of magnitude. If you used a more expensive comparison function it would probably show earlier too.
The code for swaps the heaps if is larger than , so the appended heap is always smaller than or equal to the self heap. Indeed, the slope of the rebuild method is smaller, but I can't find conditions where that is outweighed by the higher base cost of the method.
Code change:
// and about 2 * (len1 + len2) comparisons in the worst case // while `extend` takes O(len2 * log(len1)) operations // and about 1 * len2 * log_2(len1) comparisons in the worst case, <del> // assuming len1 >= len2. </del> <ins> // assuming len1 >= len2. For larger heaps, the crossover point // no longer follows this reasoning and was determined empirically. </ins> #[inline] fn better_to_rebuild(len1: usize, len2: usize) -> bool { <del> 2 * (len1 + len2) < len2 * log2_fast(len1) </del> <ins> let tot_len = len1 + len2; if tot_len <= 2048 { 2 * tot_len < len2 * log2_fast(len1) } else { 2 * tot_len < len2 * 11 } </ins> } if better_to_rebuild(self.len(), other.len()) {

Related discussion:
text: To simulate more expensive comparisons I've made a benchmark where each comparison involves some global atomic operations. Below that I've included a benchmark with ten times the number of items in the heaps in total (an order of magnitude more than that makes the benchmark very slow). The trends remain similar. ! ! The original implementation ( and ) seems to base its choice for heuristic mostly on the expectation it is a reasonable heuristic. However, I think reasoning from the worst-case scenario (O(n log(m))) is pessimistic for the method as a large number of es require only one or two comparisons (instead of log(m)) before ending up in the bottom two layers (that contain 75% of all items in the end). Maybe for even larger heaps the method actually is advantageous again, but I'm not sure how to determine a heuristic for that. <details<summaryChanged code for atomic benchmark</summary</details
Ah, I missed that. That indeed limits the opportunities to realize its advantage. The x-axis still says 50k though? First we would need a benchmark demonstrating that advantage anyway.
Only for the first image, that one has the same number of elements as before but a more expansive comparison implementation. The x-axis of the second image goes up to 500k, that one has normal "cheap" integer comparison but a larger number of items in the heaps. Certainly.
Naively, when I look at the graphs in the OP what I see isn't that extend is always going to be better -- the slopes seem to be clearly different, though two graphs with different scales and extra lines makes that comparison harder than it ought to be -- but that the current heuristic is doing a bad job of accounting for constant factors when picking the switchover point. Why isn't the answer here just use a number other than two in the heuristic?
Here's the two lines from a different measurement of the same benchmark in the same graph. It has a weird jump between and (artifact?), that's why included the more messy pictures initially. ! The slopes are indeed very different, and extrapolating them would lead to a crossover point. However, this crossover point can never actually be reached because you can't extrapolate beyond the rightmost data point.
Code change:
// and about 2 * (len1 + len2) comparisons in the worst case // while `extend` takes O(len2 * log(len1)) operations // and about 1 * len2 * log_2(len1) comparisons in the worst case, <del> // assuming len1 >= len2. </del> <ins> // assuming len1 >= len2. For larger heaps, the crossover point // no longer follows this reasoning and was determined empirically. </ins> #[inline] fn better_to_rebuild(len1: usize, len2: usize) -> bool { <del> 2 * (len1 + len2) < len2 * log2_fast(len1) </del> <ins> let tot_len = len1 + len2; if tot_len <= 2048 { 2 * tot_len < len2 * log2_fast(len1) } else { 2 * tot_len < len2 * 11 } </ins> } if better_to_rebuild(self.len(), other.len()) {

Related discussion:
text: The benchmark is set up such that two heaps are merged, one containing x elements and the other 100,000 - x. The rightmost data point at x = 50,000 corresponds to merging two equally sized heaps. The data point that would be to the right of that (x = 52,500) would give the same result as the data point to the left (x = 47,500) because both involve merging a heap of 47,500 and 52,500 elements and the heaps are swapped in one of them to make sure the smaller heap is append to the larger one. In other words, beyond the rightmost data point the slopes change (become negative) and the data would mirror the data to the left of that point (which is why I didn't include it). The crossover point is thus only reachable (in this benchmark) if you'd remove the swap-optimization (theoretically I mean, practically that would worsen performance, or course). The TLDR is that it appears the number would have to be such that the condition always evaluates to . On another note, I've now also benchmarked merging very large heaps (100 million elements after merge), and is always more favorable there as well. !
Just tried the benchmark with changes from PR and scores significantly better. The heuristic could still be improved though. !
Thanks for the update to remind me about this One thing that I'd missed last time: ing from the contents of a can never hit the worst case (needing to bubble to the root every time), since it's being extended by something that's in roughly-descending order. Do you want to wait on before looking at more?
I think for now it would be better to wait and/or work towards a better heuristic (even though can perform better, it's still up to 25% slower when the second heap is much smaller). PS/Disclaimer: I'm the author of and not a reviewer, so I may be a little biased, however the benchmarks should speak for themself. Would be nice someone else could confirm my claims
Nice performance improvements in , just a pity it makes determining the switchover heuristic more difficult ;). I ran the benchmark again with and on my machine it also improves 's performance enough that it's the faster method when merging larger heaps.
Code change:
// and about 2 * (len1 + len2) comparisons in the worst case // while `extend` takes O(len2 * log(len1)) operations // and about 1 * len2 * log_2(len1) comparisons in the worst case, <del> // assuming len1 >= len2. </del> <ins> // assuming len1 >= len2. For larger heaps, the crossover point // no longer follows this reasoning and was determined empirically. </ins> #[inline] fn better_to_rebuild(len1: usize, len2: usize) -> bool { <del> 2 * (len1 + len2) < len2 * log2_fast(len1) </del> <ins> let tot_len = len1 + len2; if tot_len <= 2048 { 2 * tot_len < len2 * log2_fast(len1) } else { 2 * tot_len < len2 * 11 } </ins> } if better_to_rebuild(self.len(), other.len()) {

Related discussion:
text: I guess it doesn't make much sense to merge as-is because of that. I'll have a look if I can determine a better heuristic based on the improved performance.
In order to determine the new switchover point, I ran some benchmarks for heaps of different lengths. For a constant total heap length (heap length after the operation), the execution time has an (approximately) linear relationship with the length of the smaller heap. This means the data can be fitted with a least-squares linear fit: ! The blue line is the rebuild strategy, and purple the extend strategy. The green vertical line indicates the intersection of the fitted lines, i.e. where the switchover between strategies should ideally be. The red vertical line indicates the switchover point using the current heuristic. The fits for all the different other lengths can be found in the collapsible section at the end of this comment. I've plotted the location of the ideal switchover point as a function of the total heap length (the current heuristic is not a smooth curve because it uses a fast but inexact log2): ! I think a couple points are noteworthy: The current heuristic is quite close to the ideal point for smaller heaps. The switchover point stays roughly constant (when considered as a percentage as in the graph above) for heap lengths 1000 to . For larger heaps, the ideal switchover point rises again, which is not reflected in the current heuristic. I am not sure how to best model a heuristic for larger heaps, especially because for the power-of-2 heaps show it drops again for the two largest heaps. However, I think it should be fairly straightforward to improve the current heuristic by setting a lower bound on the switchover point: This results in the green curve in the graph above. It is closer to the ideal switchover point in all cases, but for larger heaps it is still suboptimal. I'd love to hear ideas on how to improve the heuristic further for larger heaps. <details<summaryImages of all fits</summaryIn all graphs, blue is the rebuild strategy and purple the extend strategy. The dots indicate raw data points and the line is a least-squares linear fit. The green vertical line indicates the intersection of the fitted lines, i.e. where the switchover between strategies should ideally be.
Code change:
// and about 2 * (len1 + len2) comparisons in the worst case // while `extend` takes O(len2 * log(len1)) operations // and about 1 * len2 * log_2(len1) comparisons in the worst case, <del> // assuming len1 >= len2. </del> <ins> // assuming len1 >= len2. For larger heaps, the crossover point // no longer follows this reasoning and was determined empirically. </ins> #[inline] fn better_to_rebuild(len1: usize, len2: usize) -> bool { <del> 2 * (len1 + len2) < len2 * log2_fast(len1) </del> <ins> let tot_len = len1 + len2; if tot_len <= 2048 { 2 * tot_len < len2 * log2_fast(len1) } else { 2 * tot_len < len2 * 11 } </ins> } if better_to_rebuild(self.len(), other.len()) {

Related discussion:
text: The red vertical line indicates the current switchover point. ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! </details
Code change:
} _ => token.span, }, <del> Some(tree) => tree.span(), None => colon_span, </del> <ins> // Invalid, return a nice source location _ => colon_span.with_lo(start_sp.lo()), </ins> } } <del> Some(tree) => tree.span(), None => start_sp, </del> <ins> // Whether it's none or some other tree, it doesn't belong to // the current meta variable, returning the original span. _ => start_sp, </ins> }; result.push(TokenTree::MetaVarDecl(span, ident, None));

Related discussion:
text: Here's some code incorrectly defining a macro, because it's missing a fragment specifier. Here's the error message rustc gives me: It's potentially confusing that the error points to the source after the name with the missing fragment specifier. Especially in a complicated macro, it would be better if it pointed to the item which was actually missing the fragment specifier. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
claim
Some more context at
Code change:
<ins> #![feature(fn_traits, unboxed_closures)] fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {} struct Compose<F,G>(F,G); impl<T,F,G> FnOnce<(T,)> for Compose<F,G> where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> { type Output = G::Output; extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output { (self.1)((self.0)(x)) } } fn bad<T>(f: fn(&'static str) -> T) { test(Compose(f, |_| {})); //~ ERROR: mismatched types } fn main() {} </ins>

Related discussion:
text: Reproduction branch: When applying the change from the last commit I get a panic in my code during the call to . <details<summaryBacktrace</summary</details
Cannot reproduce on my linux. Can you provide a small ? Is that possible? Maybe without all the externals :/
I can reproduce a very similar problem (appears to involve the same origin and failing assertion of ) compiling rust-lang/regex with and compiler flags: For me, setting to 2 or greater is required to present this failure. <details<summarybacktrace</summary<code<preRUSTBACKTRACE=1 cargo build Compiling regex v1.1.2 (/home/kent/rust/regex) thread 'rustc' panicked at 'assertion failed: bpos.tou32() = () + as u32', stack backtrace: 0: std::sys::unix::backtrace::tracing::imp::unwindbacktrace at 1: std::syscommon::backtrace::print at 2: std::panicking::defaulthook::{{closure}} at at 3: std::panicking::defaulthook at 4: rustc::util::common::panichook 5: std::panicking::rustpanicwithhook at 6: std::panicking::beginpanic 7: syntax::sourcemap::SourceMap::bytepostofilecharpos 8: syntax::sourcemap::SourceMap::lookupcharpos 9: <rustccodegenssa::mir::FunctionCx<'a, 'tcx, Bx::scopemetadataforloc 10: <rustccodegenssa::mir::FunctionCx<'a, 'tcx,
Code change:
<ins> #![feature(fn_traits, unboxed_closures)] fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {} struct Compose<F,G>(F,G); impl<T,F,G> FnOnce<(T,)> for Compose<F,G> where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> { type Output = G::Output; extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output { (self.1)((self.0)(x)) } } fn bad<T>(f: fn(&'static str) -> T) { test(Compose(f, |_| {})); //~ ERROR: mismatched types } fn main() {} </ins>

Related discussion:
text: Bx::debugloc 11: rustccodegenssa::mir::codegenmir 12: rustccodegenssa::base::codegeninstance 13: rustccodegenssa::monoitem::MonoItemExt::define 14: rustccodegenllvm::base::compilecodegenunit::modulecodegen 15: rustc::depgraph::graph::DepGraph::withtask 16: rustccodegenllvm::base::compilecodegenunit 17: rustccodegenssa::base::codegencrate 18: <rustccodegenllvm::LlvmCodegenBackend as rustccodegenutils::codegenbackend::CodegenBackend::codegencrate 19: rustc::util::common::time 20: rustcdriver::driver::phase4codegen 21: rustcdriver::driver::compileinput::{{closure}} 22: <std::thread::local::LocalKey<T::with 23: rustc::ty::context::TyCtxt::createandenter 24: rustcdriver::driver::compileinput 25: rustcdriver::runcompilerwithpool 26: <scopedtls::ScopedKey<T::set 27: rustcdriver::runcompiler 28: syntax::withglobals 29: rustmaybecatchpanic at 30: <F as alloc::boxed::FnBox<A::callbox 31: std::sys::unix::thread::Thread::new::threadstart at at at 32: <unknown33: clone query stack during panic: end of query stack error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: note: rustc 1.34.0-nightly ( 2019-02-26) running on x86_64-unknown-linux-gnu note: compiler flags: -Z mir-opt-level=2 -C debuginfo=2 -C incremental --crate-type lib </pre</code</details
With the help of , I've found a tiny test that reproduces this crash on Linux and Mac:
Got another one: <details</detailsHappens when compiling regex tests with and calling on every span found in the mir of the functions needing codegen.
According to glaicer, the ICE from this example has been gone.
can you confirm that your example does not crash on nightly anymore?
Code change:
<ins> #![feature(fn_traits, unboxed_closures)] fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {} struct Compose<F,G>(F,G); impl<T,F,G> FnOnce<(T,)> for Compose<F,G> where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> { type Output = G::Output; extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output { (self.1)((self.0)(x)) } } fn bad<T>(f: fn(&'static str) -> T) { test(Compose(f, |_| {})); //~ ERROR: mismatched types } fn main() {} </ins>

Related discussion:
text: Has been fixed in
is likely the part of the rollup fixing it.
Shouldn't a testcase be instead of closing this?
A similar crash that still happens: