Skip to content

Commit 01a5777

Browse files
committed
Prefer __index__ over __int__ in ModuleOps
1 parent 368df74 commit 01a5777

File tree

3 files changed

+56
-67
lines changed

3 files changed

+56
-67
lines changed

src/core/IronPython.Modules/ModuleOps.cs

Lines changed: 31 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,6 @@ public static IntPtr GetPointer(object value) {
297297
}
298298

299299
if (value is int iVal) {
300-
if(iVal > int.MaxValue) {
301-
iVal = -1;
302-
}
303300
return new IntPtr(iVal);
304301
}
305302

@@ -356,13 +353,8 @@ public static IntPtr GetObject(object value) {
356353
}
357354

358355
public static long GetSignedLongLong(object value, object type) {
359-
int? res = Converter.ImplicitConvertToInt32(value);
360-
if (res != null) {
361-
return res.Value;
362-
}
363-
364-
if (value is BigInteger) {
365-
return (long)(BigInteger)value;
356+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
357+
return (long)bi;
366358
}
367359

368360
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -373,13 +365,8 @@ public static long GetSignedLongLong(object value, object type) {
373365
}
374366

375367
public static long GetUnsignedLongLong(object value, object type) {
376-
int? res = Converter.ImplicitConvertToInt32(value);
377-
if (res != null && res.Value >= 0) {
378-
return res.Value;
379-
}
380-
381-
if (value is BigInteger) {
382-
return (long)(ulong)(BigInteger)value;
368+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
369+
return unchecked((long)(ulong)bi);
383370
}
384371

385372
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -462,17 +449,13 @@ public static int GetSingleBits(object value) {
462449
}
463450

464451
public static int GetSignedLong(object value, object type) {
465-
if (value is int) {
466-
return (int)value;
467-
}
468-
469-
int? res = Converter.ImplicitConvertToInt32(value);
470-
if (res != null) {
471-
return res.Value;
472-
}
473-
474-
if (value is BigInteger && ((BigInteger)value).AsUInt32(out uint unsigned)) {
475-
return (int)unsigned;
452+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
453+
// This strange conversion to UInt32 was introduced in ipy2 on 20011-06-18, commit 9bf42cbf: Fix issue with marshalling int value
454+
if (bi.AsUInt32(out uint unsigned)) {
455+
return unchecked((int)unsigned);
456+
} else {
457+
return (int)bi;
458+
}
476459
}
477460

478461
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -483,14 +466,11 @@ public static int GetSignedLong(object value, object type) {
483466
}
484467

485468
public static int GetUnsignedLong(object value, object type) {
486-
int? res = Converter.ImplicitConvertToInt32(value);
487-
if (res != null) {
488-
return res.Value;
489-
}
490-
491-
if (value is BigInteger) {
492-
if (((BigInteger)value).AsUInt32(out uint ures)) {
493-
return (int)ures;
469+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
470+
if (bi.AsInt32(out int signed)) {
471+
return signed;
472+
} else {
473+
return unchecked((int)(uint)bi);
494474
}
495475
}
496476

@@ -502,23 +482,22 @@ public static int GetUnsignedLong(object value, object type) {
502482
}
503483

504484
public static int GetUnsignedInt(object value, object type) {
505-
int? res = Converter.ImplicitConvertToInt32(value);
506-
if (res != null && res.Value >= 0) {
507-
return res.Value;
485+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
486+
return unchecked((int)(uint)bi);
508487
}
509488

510489
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
511-
return GetUnsignedInt(type, asParam);
490+
return GetUnsignedInt(asParam, type);
512491
}
513492

514493
throw PythonOps.TypeErrorForTypeMismatch("unsigned int", value);
515494
}
516495

517496
public static int GetSignedInt(object value, object type) {
518-
int? res = Converter.ImplicitConvertToInt32(value);
519-
if (res != null) {
520-
return res.Value;
497+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
498+
return (int)bi;
521499
}
500+
522501
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
523502
return GetSignedInt(asParam, type);
524503
}
@@ -527,13 +506,10 @@ public static int GetSignedInt(object value, object type) {
527506
}
528507

529508
public static short GetUnsignedShort(object value, object type) {
530-
int? res = Converter.ImplicitConvertToInt32(value);
531-
if (res != null) {
532-
int iVal = res.Value;
533-
if (iVal >= ushort.MinValue && iVal <= ushort.MaxValue) {
534-
return (short)(ushort)iVal;
535-
}
509+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
510+
return unchecked((short)(ushort)bi);
536511
}
512+
537513
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
538514
return GetUnsignedShort(asParam, type);
539515
}
@@ -542,12 +518,8 @@ public static short GetUnsignedShort(object value, object type) {
542518
}
543519

544520
public static short GetSignedShort(object value, object type) {
545-
int? res = Converter.ImplicitConvertToInt32(value);
546-
if (res != null) {
547-
int iVal = res.Value;
548-
return (short)iVal;
549-
} else if (value is BigInteger bigInt) {
550-
return (short)(int)(bigInt & 0xffff);
521+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
522+
return (short)bi;
551523
}
552524

553525
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -562,9 +534,8 @@ public static int GetVariantBool(object value, object type) {
562534
}
563535

564536
public static byte GetUnsignedByte(object value, object type) {
565-
int? res = Converter.ImplicitConvertToInt32(value);
566-
if (res != null) {
567-
return (byte)res.Value;
537+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
538+
return (byte)bi;
568539
}
569540

570541
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -575,12 +546,8 @@ public static byte GetUnsignedByte(object value, object type) {
575546
}
576547

577548
public static byte GetSignedByte(object value, object type) {
578-
int? res = Converter.ImplicitConvertToInt32(value);
579-
if (res != null) {
580-
int iVal = res.Value;
581-
if (iVal >= sbyte.MinValue && iVal <= sbyte.MaxValue) {
582-
return (byte)(sbyte)iVal;
583-
}
549+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
550+
return unchecked((byte)(sbyte)bi);
584551
}
585552

586553
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {

src/core/IronPython.Modules/_opcode.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#nullable enable
66

7+
using System.Numerics;
8+
79
using IronPython.Runtime;
810
using IronPython.Runtime.Operations;
911

@@ -155,10 +157,10 @@ public static int stack_effect(CodeContext context, int opcode, object? oparg =
155157
throw PythonOps.ValueError("stack_effect: opcode requires oparg but oparg was not specified");
156158
}
157159

158-
if (!Converter.TryConvertToIndex(oparg, out ioparg)) { // supported since CPython 3.8
159-
ioparg = Converter.ImplicitConvertToInt32(oparg) ?? // warning since CPython 3.8, unsupported in 3.10
160-
throw PythonOps.TypeError($"an integer is required (got type {PythonOps.GetPythonTypeName(oparg)})");
160+
if (!PythonOps.TryToInt(oparg, out BigInteger bioparg)) {
161+
throw PythonOps.TypeError($"an integer is required (got type {PythonOps.GetPythonTypeName(oparg)})");
161162
}
163+
ioparg = (int)bioparg;
162164
} else if (oparg != null) {
163165
throw PythonOps.ValueError("stack_effect: opcode does not permit oparg but oparg was specified");
164166
}

src/core/IronPython/Runtime/Operations/PythonOps.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,26 @@ internal static bool TryToIndex(object? o, out BigInteger index) {
877877
return false;
878878
}
879879

880+
// This method is like `TryToIndex` but it additionally supports objects with `__int__`,
881+
// which is expected for Python 3.7- and is supported until Python 3.10.
882+
internal static bool TryToInt(object? o, out BigInteger res) {
883+
if (TryToIndex(o, out res)) {
884+
// supported since Python 3.8
885+
return true;
886+
}
887+
if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__int__", out object objres)) {
888+
// warning since Python 3.8, unsupported in 3.10
889+
res = objres switch {
890+
int i => i,
891+
BigInteger bi => bi,
892+
Extensible<BigInteger> ebi => ebi.Value,
893+
_ => throw TypeError("__int__ returned non-int (type {0})", PythonOps.GetPythonTypeName(objres))
894+
};
895+
return true;
896+
}
897+
return false;
898+
}
899+
880900
private static bool IndexObjectToInt(object o, out int res, out BigInteger longRes) {
881901
switch (o) {
882902
case int i:

0 commit comments

Comments
 (0)