crash: compile-time typeck/check.rs failure #3668

Closed
BigEndian opened this Issue Oct 6, 2012 · 4 comments

Projects

None yet

3 participants

@BigEndian

Result of attempted compilation:

rust: task failed at 'Assertion fcx.inh.locals.contains_key(nid) failed', /Users/superjapanfreak/build/rust/src/rustc/middle/typeck/check.rs:2388
error: internal compiler error: unexpected failure
note: the compiler hit an unexpected failure path. this is a bug
note: try running with RUST_LOG=rustc=0,::rt::backtrace to get further details and report the results to github.com/mozilla/rust/issues
rust: task failed at 'explicit failure', /Users/superjapanfreak/build/rust/src/rustc/driver/rustc.rs:275
rust: domain main @0x7fb97b800010 root task failed
rust: task failed at 'killed', /Users/superjapanfreak/build/rust/src/libcore/task.rs:705
struct Employee { name: ~str, mut employer: Option<@Business> }                                                                                                                    
struct Business { name: ~str, mut boss: Option<@mut Employee>, mut employees: ~[Option<@mut Employee>] }                                                                           

trait EmployeeTrait {                                                                                                                                                              
   pure fn isEmployed() -> bool;                                                                                                                                                   
   fn setEmployer(employer: @Business);                                                                                                                                            
}                                                                                                                                                                                  

impl Employee: EmployeeTrait {                                                                                                                                                        pure fn isEmployed() -> bool {                                                                                                                                                        self.employer.is_some()                                                                                                                                                      
   }                                                                                                                                                                               
   fn setEmployer(employer: @Business) {                                                                                                                                           
      self.employer = Some(employer);                                                                                                                                              
   }                                                                                                                                                                               
}                                                                                                                                                                                  

trait BusinessTrait {                                                                                                                                                              
   fn fireBoss() -> bool;                                                                                                                                                          
   fn hireBoss(e: @mut Employee);                                                                                                                                                  
   fn getBossOption() -> Option<@Employee>;                                                                                                                                        
}                                                                                                                                                                                  

impl Business: BusinessTrait {                                                                                                                                                     
   fn fireBoss() -> bool {                                                                                                                                                         
      if self.boss.is_none() {                                                                                                                                                     
         return false;                                                                                                                                                             
      }                                                                                                                                                                            
      let oldBoss = self.boss.get();                                                                                                                                               
      oldBoss.employer = None;                                                                                                                                                     
      self.boss = None;                                                                                                                                                            
      true                                                                                                                                                                         
   }                                                                                                                                                                               
   fn hireBoss(newBoss: @mut Employee) {                                                                                                                                           
      if self.boss.is_some() {                                                                                                                                                     
         self.fireBoss();                                                                                                                                                          
      }                                                                                                                                                                            
      newBoss.setEmployer(@copy self);                                                                                                                                             
      self.boss = Some(newBoss);                                                                                                                                                   
   }                                                                                                                                                                               
   fn getBossOption() -> Option<@Employee> {                                                                                                                                       
      let opt: Option<@Employee> = None;                                                                                                                                           
      if self.boss.is_some() {                                                                                                                                                     
         const bossCopy: @Employee = self.boss.get();                                                                                                                              
         opt = Some(bossCopy);                                                                                                                                                     
      }                                                                                                                                                                            
      opt                                                                                                                                                                          
   }                                                                                                                                                                               
}                                                                                                                                                                                  

fn main() {                                                                                                                                                                        
   let bob = @mut Employee { name: ~"Bob Newhart", employer: None };
   let restaurant = Business { name: ~"In-N-Out", boss: Some(bob), employees: ~[] };                                                                                               

   io::println(#fmt("Bob is %s", if bob.isEmployed() { ~"employed" } else { ~"not employed" }));                                                                                   
} 
@BigEndian

Updated test case:

struct P { child: Option<@mut P> }                                                                                                                                                                                                                                                                                                                                    
trait PTrait {                                                                                                                                                                     
   fn getChildOption() -> Option<@P>;                                                                                                                                              
}                                                                                                                                                                                  

impl P: PTrait {                                                                                                                                                                   
   fn getChildOption() -> Option<@P> {                                                                                                                                             
      let opt: Option<@P> = None;                                                                                                                                                        if self.child.is_some() {                                                                                                                                                             const childVal: @P = self.child.get();                                                                                                                                    
         opt = Some(childVal);                                                                                                                                                     
      }                                                                                                                                                                            
      opt                                                                                                                                                                          
   }                                                                                                                                                                               
}
@catamorphism catamorphism was assigned Oct 6, 2012
@catamorphism

I'll take a look while waiting for snapshots to finish...

@catamorphism

An even smaller program that exhibits the same bug:

fn f(x:int) {
    const child: int = x + 1;
}

fn main() {}

The problem is that this isn't an acceptable RHS for a constant, as in your example as well. But, constant checking happens after typechecking. The typechecker, though, assumes constants don't refer to things like self or args. This is a bad assumption to make. To fix this, either we have to pass a function context to checking nested consts, or check constants before typechecking (constant checking uses some tables generated by the typechecker, though). It's a pain either way. But should be fixed.

@nikomatsakis
Collaborator

This seems like a resolve bug. Resolve should understand the scoping for constant declarations.

@catamorphism catamorphism added a commit that referenced this issue Oct 15, 2012
@catamorphism catamorphism Add test cases for #3668
Previous commits fix the issue.

Closes #3668
c5b82a6
@catamorphism catamorphism added a commit that closed this issue Oct 15, 2012
@catamorphism catamorphism Add test cases for #3668
Previous commits fix the issue.

Closes #3668
c5b82a6
@catamorphism catamorphism was unassigned by BigEndian Jun 16, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment