Add support for destructuring vectors in match expressions · rust-lang/rust@1968cb3 (original) (raw)

`@@ -22,6 +22,7 @@ use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat, walk_pat};

`

22

22

`use syntax::codemap::span;

`

23

23

`use syntax::print::pprust::pat_to_str;

`

24

24

`use syntax::visit;

`

``

25

`+

use std::sort;

`

25

26

``

26

27

`struct AltCheckCtxt {

`

27

28

`tcx: ty::ctxt,

`

`@@ -146,6 +147,12 @@ fn check_exhaustive(cx: @AltCheckCtxt, sp: span, pats: ~[@pat]) {

`

146

147

`None => fail ~"check_exhaustive: bad variant in ctor"

`

147

148

`}

`

148

149

`}

`

``

150

`+

ty::ty_unboxed_vec() | ty::ty_evec() => {

`

``

151

`+

match (*ctor) {

`

``

152

`+

vec(n) => Some(fmt!("vectors of length %u", n)),

`

``

153

`+

_ => None

`

``

154

`+

}

`

``

155

`+

}

`

149

156

` _ => None

`

150

157

`}

`

151

158

`}

`

`@@ -166,6 +173,8 @@ enum ctor {

`

166

173

` variant(def_id),

`

167

174

` val(const_val),

`

168

175

` range(const_val, const_val),

`

``

176

`+

vec(uint),

`

``

177

`+

vec_with_tail(uint)

`

169

178

`}

`

170

179

``

171

180

`impl ctor : cmp::Eq {

`

`@@ -179,7 +188,12 @@ impl ctor : cmp::Eq {

`

179

188

` range(ref cv0_other, ref cv1_other)) => {

`

180

189

`(*cv0_self) == (*cv0_other) && (*cv1_self) == (*cv1_other)

`

181

190

`}

`

182

``

`-

(single, ) | (variant(), ) | (val(), _) | (range(*), _) => {

`

``

191

`+

(vec(n_self), vec(n_other)) => n_self == n_other,

`

``

192

`+

(vec_with_tail(n_self), vec_with_tail(n_other)) => {

`

``

193

`+

n_self == n_other

`

``

194

`+

}

`

``

195

`+

(single, ) | (variant(), ) | (val(), _) |

`

``

196

`+

(range(), _) | (vec(), _) | (vec_with_tail(*), _) => {

`

183

197

`false

`

184

198

`}

`

185

199

`}

`

`@@ -236,6 +250,21 @@ fn is_useful(cx: @AltCheckCtxt, m: matrix, v: ~[@pat]) -> useful {

`

236

250

`}

`

237

251

` not_useful

`

238

252

`}

`

``

253

`+

ty::ty_unboxed_vec() | ty::ty_evec() => {

`

``

254

`+

let max_len = do m.foldr(0) |r, max_len| {

`

``

255

`+

match r[0].node {

`

``

256

`+

pat_vec(elems, _) => uint::max(elems.len(), max_len),

`

``

257

`+

_ => max_len

`

``

258

`+

}

`

``

259

`+

};

`

``

260

`+

for uint::range(0, max_len + 1) |n| {

`

``

261

`+

match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {

`

``

262

`+

not_useful => (),

`

``

263

`+

ref u => return (*u)

`

``

264

`+

}

`

``

265

`+

}

`

``

266

`+

not_useful

`

``

267

`+

}

`

239

268

` _ => {

`

240

269

`let arity = ctor_arity(cx, single, left_ty);

`

241

270

`is_useful_specialized(cx, m, v, single, arity, left_ty)

`

`@@ -297,6 +326,12 @@ fn pat_ctor_id(cx: @AltCheckCtxt, p: @pat) -> Option {

`

297

326

` pat_region(*) => {

`

298

327

`Some(single)

`

299

328

`}

`

``

329

`+

pat_vec(elems, tail) => {

`

``

330

`+

match tail {

`

``

331

`+

Some(_) => Some(vec_with_tail(elems.len())),

`

``

332

`+

None => Some(vec(elems.len()))

`

``

333

`+

}

`

``

334

`+

}

`

300

335

`}

`

301

336

`}

`

302

337

``

`@@ -360,6 +395,56 @@ fn missing_ctor(cx: @AltCheckCtxt,

`

360

395

`else if true_found { Some(val(const_bool(false))) }

`

361

396

`else { Some(val(const_bool(true))) }

`

362

397

`}

`

``

398

`+

ty::ty_unboxed_vec() | ty::ty_evec() => {

`

``

399

`+

let max_len = do m.foldr(0) |r, max_len| {

`

``

400

`+

match r[0].node {

`

``

401

`+

pat_vec(elems, _) => uint::max(elems.len(), max_len),

`

``

402

`+

_ => max_len

`

``

403

`+

}

`

``

404

`+

};

`

``

405

`+

let min_len_with_tail = do m.foldr(max_len + 1) |r, min_len| {

`

``

406

`+

match r[0].node {

`

``

407

`+

pat_vec(elems, tail) => {

`

``

408

`+

if tail.is_some() && elems.len() < min_len {

`

``

409

`+

elems.len()

`

``

410

`+

} else {

`

``

411

`+

min_len

`

``

412

`+

}

`

``

413

`+

}

`

``

414

`+

_ => min_len

`

``

415

`+

}

`

``

416

`+

};

`

``

417

`+

let vec_lens = do m.filter_map |r| {

`

``

418

`+

match r[0].node {

`

``

419

`+

pat_vec(elems, tail) => {

`

``

420

`+

match tail {

`

``

421

`+

None if elems.len() < min_len_with_tail => Some(elems.len()),

`

``

422

`+

_ => None

`

``

423

`+

}

`

``

424

`+

}

`

``

425

`+

_ => None

`

``

426

`+

}

`

``

427

`+

};

`

``

428

`+

let mut sorted_vec_lens = do sort::merge_sort(vec_lens) |a, b| {

`

``

429

`+

a < b

`

``

430

`+

};

`

``

431

`+

vec::dedup(&mut sorted_vec_lens);

`

``

432

+

``

433

`+

let mut missing = None;

`

``

434

`+

for uint::range(0, min_len_with_tail) |i| {

`

``

435

`+

if i >= sorted_vec_lens.len() || i != sorted_vec_lens[i] {

`

``

436

`+

missing = Some(i);

`

``

437

`+

break;

`

``

438

`+

}

`

``

439

`+

};

`

``

440

`+

if missing.is_none() && min_len_with_tail > max_len {

`

``

441

`+

missing = Some(min_len_with_tail);

`

``

442

`+

}

`

``

443

`+

match missing {

`

``

444

`+

Some(k) => Some(vec(k)),

`

``

445

`+

None => None

`

``

446

`+

}

`

``

447

`+

}

`

363

448

` _ => Some(single)

`

364

449

`}

`

365

450

`}

`

`@@ -378,6 +463,12 @@ fn ctor_arity(cx: @AltCheckCtxt, ctor: ctor, ty: ty::t) -> uint {

`

378

463

`}

`

379

464

`}

`

380

465

` ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),

`

``

466

`+

ty::ty_unboxed_vec() | ty::ty_evec() => {

`

``

467

`+

match ctor {

`

``

468

`+

vec(n) | vec_with_tail(n) => n,

`

``

469

`+

_ => 0u

`

``

470

`+

}

`

``

471

`+

}

`

381

472

` _ => 0u

`

382

473

`}

`

383

474

`}

`

`@@ -521,6 +612,32 @@ fn specialize(cx: @AltCheckCtxt, r: ~[@pat], ctor_id: ctor, arity: uint,

`

521

612

`compare_const_vals(c_hi, v_hi) <= 0;

`

522

613

`if match_ { Some(vec::tail(r)) } else { None }

`

523

614

`}

`

``

615

`+

pat_vec(elems, tail) => {

`

``

616

`+

match ctor_id {

`

``

617

`+

vec_with_tail(_) => {

`

``

618

`+

if elems.len() >= arity {

`

``

619

`+

Some(vec::append(elems.slice(0, arity), vec::tail(r)))

`

``

620

`+

} else {

`

``

621

`+

None

`

``

622

`+

}

`

``

623

`+

}

`

``

624

`+

vec(_) => {

`

``

625

`+

if elems.len() < arity && tail.is_some() {

`

``

626

`+

Some(vec::append(

`

``

627

`+

vec::append(elems, vec::from_elem(

`

``

628

`+

arity - elems.len(), wild())

`

``

629

`+

),

`

``

630

`+

vec::tail(r)

`

``

631

`+

))

`

``

632

`+

} else if elems.len() == arity {

`

``

633

`+

Some(vec::append(elems, vec::tail(r)))

`

``

634

`+

} else {

`

``

635

`+

None

`

``

636

`+

}

`

``

637

`+

}

`

``

638

`+

_ => None

`

``

639

`+

}

`

``

640

`+

}

`

524

641

`}

`

525

642

`}

`

526

643

``

`@@ -593,6 +710,7 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool {

`

593

710

` args.any(|a| is_refutable(cx, *a))

`

594

711

`}

`

595

712

` pat_enum(,) => { false }

`

``

713

`+

pat_vec(*) => { true }

`

596

714

`}

`

597

715

`}

`

598

716

``